// game.cpp : Defines the entry point for the application.
//

/**
T这不是最终版本的平台层
1. 存档位置
2. 获取自己可执行文件的句柄
3. 资源加载路径
4. 线程（启动线程）
5. 原始输入（支持多个键盘）
6. Sleep/TimeBeginPeriod
7. ClipCursor()（多显示器支持）
8. 全屏支持
9. WM_SETCURSOR（控制光标可见性）
10. QueryCancelAutoplay
11. WM_ACTIVATEAPP（当我们不是活动应用程序时）
12. Blit速度优化（BitBlt）
13. 硬件加速（OpenGL或Direct3D或两者？）
14. GetKeyboardLayout（支持法语键盘、国际化WASD键支持）
只是一个部分清单
*/
#include <iostream>
#include "win32_game.h"
#include "game.h"
#include <xinput.h>
#include <gl/gl.h>
#include "game_opengl.h"
#include "game_render.h"
#include "game_render.h"
#include "game_config.h"
#include "game_platform.h"

global_variable bool32 GlobalSoftwareRendering = false;
extern GLuint GlobalBlitTextureHandle;
global_variable bool32 DEBUGGlobalShowCursor;
global_variable WINDOWPLACEMENT GlobalWindowPosition = {sizeof(GlobalWindowPosition)};

typedef BOOL wgl_get_pixel_format_attrib_iv_arb(HDC hdc, int iPixelFormat, int iLayerPlane,
                                                UINT nAttributes, const int *piAttributes,
                                                int *piValues);

typedef BOOL wgl_get_pixel_format_attrib_fv_arb(HDC hdc, int iPixelFormat, int iLayerPlane,
                                                UINT nAttributes, const int *piAttributes,
                                                FLOAT *pfValues);

typedef BOOL wgl_choose_pixel_format_arb(HDC hdc, const int *piAttribIList,
                                         const FLOAT *pfAttribFList, UINT nMaxFormats,
                                         int *piFormats, UINT *nNumFormats);

typedef HGLRC WINAPI wgl_create_context_attribts_arb(HDC hDC, HGLRC hShareContext,
                                                     const int *attribList);
typedef const char *wgl_get_extensions_string_ext(void);
typedef BOOL WINAPI wgl_swap_interval_ext(int interval);

global_variable wgl_swap_interval_ext *wglSwapIntervalEXT;
global_variable wgl_create_context_attribts_arb *wglCreateContextAttribsARB;
global_variable wgl_choose_pixel_format_arb *wglChoosePixelFormatARB;
global_variable wgl_get_extensions_string_ext *wglGetExtensionsStringEXT;
global_variable bool32 OpenGLSupportsSRGBFrameBuffer;
global_variable GLuint OpenGLReservedBlitTexture;

internal void ToggleFullscreen(HWND Window) {
    DWORD Style = GetWindowLong(Window, GWL_STYLE);  // 获取当前窗口的样式标志

    if (Style & WS_OVERLAPPEDWINDOW) {  // 如果窗口当前是一个常规的重叠窗口
        MONITORINFO MonitorInfo = {
            sizeof(MonitorInfo)};  // 创建一个 MONITORINFO 结构，用于存储显示器信息

        // 获取当前窗口的位置和大小，并获取该窗口所在的显示器信息
        if (GetWindowPlacement(Window, &GlobalWindowPosition) &&
            GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTONEAREST), &MonitorInfo)) {
            // 将窗口的样式从重叠窗口（有标题栏、边框等）改为无边框窗口
            SetWindowLong(Window, GWL_STYLE, Style & ~WS_OVERLAPPEDWINDOW);

            // 设置窗口的位置和大小为当前显示器的工作区（全屏显示）
            SetWindowPos(
                Window, HWND_TOP, MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top,
                MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left,  // 设置窗口宽度
                MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top,  // 设置窗口高度
                SWP_NOOWNERZORDER | SWP_FRAMECHANGED);  // 不改变窗口的 Z 顺序，更新窗口的边框和样式
        }
    } else {  // 如果当前窗口已经是全屏（没有边框）模式
        // 恢复窗口为一个常规的重叠窗口（恢复边框和标题栏）
        SetWindowLongA(Window, GWL_STYLE, Style | WS_OVERLAPPEDWINDOW);

        // 恢复窗口到之前的位置和大小
        SetWindowPlacement(Window, &GlobalWindowPosition);

        // 设置窗口不改变位置和大小，只更新窗口的显示状态
        SetWindowPos(Window, 0, 0, 0, 0, 0,
                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }
}
#if GAME_INTERNAL
// 释放文件读取的内存
DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUGPlatformFreeFileMemory) {
    if (Memory) {
        // 调用 VirtualFree 释放内存
        VirtualFree(Memory, 0, MEM_RELEASE);
    }
}

// 读取整个文件内容到内存
DEBUG_PLATFORM_READ_ENTIRE_FILE(DEBUGPlatformReadEntireFile) {
    // 打开文件以进行读取
    HANDLE FileHandle = CreateFileA(Filename,         // 创建文件的文件名
                                    GENERIC_READ,     // 只读访问权限
                                    FILE_SHARE_READ,  // 允许其他进程读取文件
                                    0,                // 默认安全性,NULL使用默认设置
                                    OPEN_EXISTING,    // 如果文件存在，则打开
                                    0,                // 文件属性
                                    0);               // 模板文件句柄
    debug_read_file_result Result = {};               // 初始化返回结果
    if (FileHandle != INVALID_HANDLE_VALUE) {         // 如果文件成功打开
        LARGE_INTEGER FileSize;
        if (GetFileSizeEx(FileHandle, &FileSize)) {  // 获取文件大小
            // TODO:为最大值定义宏，例如 Uin32Max
            Assert(FileSize.QuadPart <= 0xFFFFFFFF);  // 确保文件大小不超过 32 位
            uint32 FileSize32 = SafeTruncateUInt64(FileSize.QuadPart);  // 将文件大小转换为 32 位
            // 分配内存用于存储文件内容
            Result.Contents = VirtualAlloc(0,                         //
                                           FileSize32,                // 文件大小
                                           MEM_RESERVE | MEM_COMMIT,  // 保留并提交内存
                                           PAGE_READWRITE);           // 可读写内存
            if (Result.Contents) {                                    // 如果内存分配成功
                DWORD BytesRead;
                if (ReadFile(FileHandle,       //
                             Result.Contents,  //
                             FileSize32,       // 要读取的字节数
                             &BytesRead,       // 读取的字节数
                             0) &&
                    (FileSize32 == BytesRead)) {  // 如果读取的字节数与文件大小相符
                    // 注意: 文件读取成功
                    Result.ContentsSize = FileSize32;  // 设置读取内容的大小
                } else {
                    // TODO: 记录日志
                    DEBUGPlatformFreeFileMemory(Result.Contents);  // 释放内存
                    Result.Contents = 0;                           // 清空指针
                }
            } else {
                // TODO: 记录日志
            }
        } else {
            // TODO: 记录日志
        }
        CloseHandle(FileHandle);  // 关闭文件句柄
    } else {
        // TODO: 记录日志
    }
    return Result;  // 返回结果，包含文件内容和大小
}

// 将内存内容写入文件
DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DEBUGPlatformWriteFileEntireFile) {
    // 创建或打开文件以进行写入
    HANDLE FileHandle = CreateFileA(Filename,       //
                                    GENERIC_WRITE,  // 写入权限
                                    0,              // 不共享文件
                                    0,              // 默认安全性
                                    CREATE_ALWAYS,  // 如果文件存在，则覆盖
                                    0,              // 文件属性
                                    0);             // 模板文件句柄
    if (FileHandle != INVALID_HANDLE_VALUE) {       // 如果文件成功打开
        bool32 WriteResult = false;
        DWORD BytesToWritten;
        if (WriteFile(FileHandle,         //
                      Memory,             // 要写入的内存内容
                      (DWORD)MemorySize,  // 写入的字节数
                      &BytesToWritten,    // 实际写入的字节数
                      0)) {               // 如果写入成功
            // 注意: 文件写入成功
            WriteResult = (BytesToWritten == MemorySize);  // 确保写入字节数与预期一致
            (void)WriteResult;
        } else {
            // TODO: 记录日志
        }
    } else {
        // TODO: 记录日志
    }
    return FileHandle;  // 返回结果，写入成功则返回文件句柄，否则返回空
}

DEBUG_PLATFORM_EXECUTE_SYSTEM_COMMAND(DEBUGPlatformExecuteSystemCommand) {
    debug_executing_process Result = {};
    STARTUPINFO StartupInfo = {};
    StartupInfo.cb = sizeof(StartupInfo);
    StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
    StartupInfo.wShowWindow = SW_HIDE;
    PROCESS_INFORMATION ProcessInfo;
    if (CreateProcess(Command, CommandLine, 0, 0, FALSE, 0, 0, Path, &StartupInfo, &ProcessInfo)) {
        // Assert(sizeof(Result.OSHandle) >= sizeof(ProcessInfo.hProcess));
        *(HANDLE *)&Result.OSHandle = ProcessInfo.hProcess;
    } else {
        *(HANDLE *)&Result.OSHandle = INVALID_HANDLE_VALUE;
        LPVOID msgBuffer;
        DWORD ErrorCode = GetLastError();
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_IGNORE_INSERTS,
                      NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                      (LPTSTR)&msgBuffer, 0, NULL);
        std::wcout << L"Error Code " << ErrorCode << L": " << (LPCTSTR)msgBuffer << std::endl;
        LocalFree(msgBuffer);
    }
    return Result;
}

DEBUG_PLATFORM_CLOSE_FILE_HANDLE(DEBUGPlatformCloseFileHandle) {
    if (FileHandle) {
        CloseHandle(FileHandle);
    }
}

DEBUG_PLATFORM_GET_PROCESS_STATE(DEBUGPlatformGetProcessState) {
    debug_process_state Result = {};
    if (*(HANDLE *)&Process.OSHandle != INVALID_HANDLE_VALUE) {
        HANDLE hProcess = *(HANDLE *)&Process.OSHandle;
        if (WaitForSingleObject(hProcess, 0) == WAIT_OBJECT_0) {
            DWORD ReturnCode = 0;
            GetExitCodeProcess(hProcess, &ReturnCode);
            Result.ReturnCode = ReturnCode;
            CloseHandle(hProcess);
        } else {
            Result.IsRunning = true;
        }
    }
    return Result;
}
#endif  // GAME_INTERNAL

// TODO: 全局变量
// 用于控制程序运行的全局布尔变量，通常用于循环条件
global_variable bool32 GlobalRunning;
global_variable bool32 GlobalPause;
// 用于存储屏幕缓冲区的全局变量
global_variable win32_offscreen_buffer GlobalBackbuffer;
global_variable LPDIRECTSOUNDBUFFER GlobalSecondaryBuffer;
global_variable int64 GlobalPerfCountFrequency;

/**
 * @param dwUserIndex // 与设备关联的玩家索引
 * @param pState // 接收当前状态的结构体
 */
#define X_INPUT_GET_STATE(name)                           \
    DWORD WINAPI name([[maybe_unused]] DWORD dwUserIndex, \
                      [[maybe_unused]] XINPUT_STATE *pState)  // 定义一个宏，将指定名称设置为
// XInputGetState 函数的类型定义

/**
 * @param dwUserIndex // 与设备关联的玩家索引
 * @param pVibration  // 要发送到控制器的震动信息
 */
#define X_INPUT_SET_STATE(name)             \
    DWORD WINAPI name(                      \
        [[maybe_unused]] DWORD dwUserIndex, \
        [[maybe_unused]] XINPUT_VIBRATION *pVibration)  // 定义一个宏，将指定名称设置为
                                                        // XInputSetState 函数的类型定义

typedef X_INPUT_GET_STATE(x_input_get_state);
// 定义了 x_input_get_state 类型，为 `XInputGetState` 函数的类型
typedef X_INPUT_SET_STATE(x_input_set_state);
// 定义了 x_input_set_state 类型，为 `XInputSetState` 函数的类型

// 定义一个 XInputGetState 的打桩函数，返回值为
// ERROR_DEVICE_NOT_CONNECTED，表示设备未连接
X_INPUT_GET_STATE(XInputGetStateStub) {  //
    return (ERROR_DEVICE_NOT_CONNECTED);
}

// 定义一个 XInputSetState 的打桩函数，返回值为
// ERROR_DEVICE_NOT_CONNECTED，表示设备未连接
X_INPUT_SET_STATE(XInputSetStateStub) {  //
    return (ERROR_DEVICE_NOT_CONNECTED);
}

// 设置全局变量 XInputGetState_ 和 XInputSetState_ 的初始值为打桩函数
global_variable x_input_get_state *XInputGetState_ = XInputGetStateStub;
global_variable x_input_set_state *XInputSetState_ = XInputSetStateStub;

// 定义宏将 XInputGetState 和 XInputSetState 重新指向 XInputGetState_ 和
// XInputSetState_
#define XInputGetState XInputGetState_
#define XInputSetState XInputSetState_

// 定义一个结构体，用于存储与游戏代码相关的加载和调用信息
struct win32_game_code {
    HMODULE GameCodeDLL;  // 用于存储加载的游戏动态链接库句柄
    FILETIME DLLLastWriteTime;
    game_update_and_render *UpdateAndRender;  // 指向游戏更新和渲染函数的指针
    game_get_sound_samples *GetSoundSamples;  // 指向游戏音频采样获取函数的指针
#if GAME_INTERNAL
    debug_game_frame_end *DEBUGGameFrameEnd;
#endif               // GAME_INTERNAL
    bool32 IsValid;  // 用于表示加载的游戏代码是否有效
};

// 获取文件最后一次写入时间的函数
inline FILETIME Win32GetLastWriteTime(const char *Filename) {
    // 定义 WIN32_FIND_DATA 结构，保存找到的文件信息
    WIN32_FIND_DATA FindData;

    // 使用 FindFirstFile 函数查找指定文件，返回一个句柄
    HANDLE FindHandle = FindFirstFile(Filename, &FindData);

    // 定义一个 FILETIME 结构来保存最后一次写入时间
    FILETIME LastWriteTime = {};

    // 如果找到文件（句柄不等于无效句柄值），则提取文件的最后一次写入时间
    if (FindHandle != INVALID_HANDLE_VALUE) {
        // 获取文件的最后一次写入时间
        LastWriteTime = FindData.ftLastWriteTime;

        // 关闭找到的文件句柄
        FindClose(FindHandle);
    }

    // 返回文件的最后一次写入时间
    return LastWriteTime;
}

// 函数：加载游戏代码的动态链接库和关键函数
// 返回值：包含加载结果的 win32_game_code 结构体
internal win32_game_code Win32LoadGameCode(const char *SourceDLLName, const char *TempDLLName,
                                           char *LockFileName) {
    win32_game_code Result = {};  // 初始化结果结构体，默认为空
    WIN32_FILE_ATTRIBUTE_DATA Ignored;
    // 尝试获取文件属性以检查锁文件是否存在。
    if (!GetFileAttributesEx(LockFileName, GetFileExInfoStandard, &Ignored)) {
        Result.DLLLastWriteTime = Win32GetLastWriteTime(SourceDLLName);
        CopyFile(SourceDLLName,  // 源文件路径
                 TempDLLName,    // 目标文件的路径
                 false);         // FALSE：如果目标文件已存在，将覆盖目标文件。
        // 尝试加载游戏的动态链接库 (DLL)
        Result.GameCodeDLL = LoadLibraryA(TempDLLName);

        // 如果成功加载 DLL，则尝试获取关键函数的地址
        if (Result.GameCodeDLL) {
            Result.UpdateAndRender =
                (game_update_and_render *)GetProcAddress(Result.GameCodeDLL, "GameUpdateAndRender");
            Result.GetSoundSamples =
                (game_get_sound_samples *)GetProcAddress(Result.GameCodeDLL, "GameGetSoundSamples");
#if GAME_INTERNAL
            Result.DEBUGGameFrameEnd =
                (debug_game_frame_end *)GetProcAddress(Result.GameCodeDLL, "DEBUGGameFrameEnd");
#endif  // GAME_INTERNAL
        //  检查关键函数是否都成功加载
            Result.IsValid =
                (Result.UpdateAndRender && Result.GetSoundSamples && Result.DEBUGGameFrameEnd);
        }
    }
    // 如果加载失败或关键函数未找到，则使用存根函数代替
    if (!Result.IsValid) {
        Result.UpdateAndRender = 0;  // 使用默认的更新和渲染存根函数
        Result.GetSoundSamples = 0;  // 使用默认的音频采样存根函数
        Result.DEBUGGameFrameEnd = 0;
    }

    // 返回加载结果
    return Result;
}

internal void win32UnloadGameCode(win32_game_code *GameCode) {
    // 检查是否已经加载了游戏代码的动态链接库（DLL）
    if (GameCode->GameCodeDLL) {
        // 释放已经加载的游戏代码 DLL
        FreeLibrary(GameCode->GameCodeDLL);
        GameCode->GameCodeDLL = 0;
    }
    // 将游戏代码的有效性标记为无效
    GameCode->IsValid = false;
    // 将游戏的更新和渲染函数重置为存根函数
    GameCode->UpdateAndRender = 0;
    // 将获取声音样本的函数重置为存根函数
    GameCode->GetSoundSamples = 0;
}

// 加载 XInput DLL 并获取函数地址
internal void Win32LoadXInput(void) {  //
    HMODULE XInputLibrary = LoadLibrary("xinput1_4.dll");
    if (!XInputLibrary) {
        // 如果无法加载 xinput1_4.dll，则回退到 xinput1_3.dll
        XInputLibrary = LoadLibrary("xinput1_3.dll");
    } else {
        // TODO:Diagnostic
    }
    if (XInputLibrary) {  // 检查库是否加载成功
        XInputGetState = (x_input_get_state *)GetProcAddress(
            XInputLibrary, "XInputGetState");  // 获取 XInputGetState 函数地址
        if (!XInputGetState) {                 // 如果获取失败，使用打桩函数
            XInputGetState = XInputGetStateStub;
        }
        XInputSetState = (x_input_set_state *)GetProcAddress(
            XInputLibrary, "XInputSetState");  // 获取 XInputSetState 函数地址
        if (!XInputSetState) {                 // 如果获取失败，使用打桩函数
            XInputSetState = XInputSetStateStub;
        }
    } else {
        // TODO:Diagnostic
    }
}

#define DIRECT_SOUND_CREATE(name) \
    HRESULT WINAPI name(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
// 定义一个宏，用于声明 DirectSound 创建函数的原型

typedef DIRECT_SOUND_CREATE(direct_sound_create);
// 定义一个类型别名 direct_sound_create，代表
// DirectSound 创建函数

internal void Win32InitDSound(HWND window, int32 SamplesPerSecond, int32 BufferSize) {
    // 注意: 加载 dsound.dll 动态链接库
    HMODULE DSoundLibrary = LoadLibraryA("dsound.dll");
    if (DSoundLibrary) {
        // 注意: 获取 DirectSound 创建函数的地址
        // 通过 GetProcAddress 函数查找 "DirectSoundCreate" 函数在 dsound.dll
        // 中的地址，并将其转换为 direct_sound_create 类型的函数指针
        direct_sound_create *DirectSoundCreate =
            (direct_sound_create *)GetProcAddress(DSoundLibrary, "DirectSoundCreate");
        // 定义一个指向 IDirectSound 接口的指针，并初始化为 NULL
        IDirectSound *DirectSound = NULL;
        if (DirectSoundCreate &&
            SUCCEEDED(DirectSoundCreate(0,
                                        // 传入 0 作为设备 GUID，表示使用默认音频设备
                                        &DirectSound,
                                        // 将创建的 DirectSound 对象的指针存储到
                                        // DirectSound 变量中
                                        0
                                        // 传入 0 作为外部未知接口指针，通常为 NULL
                                        )))  //
        {
            // clang-format off
      WAVEFORMATEX WaveFormat = {};
      WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // 设置格式标签为 WAVE_FORMAT_PCM，表示使用未压缩的 PCM 格式
      WaveFormat.nChannels = 2;          // 设置声道数为 2，表示立体声（两个声道：左声道和右声道）
      WaveFormat.nSamplesPerSec = SamplesPerSecond; // 采样率 表示每秒钟的样本数，常见值为 44100 或 48000 等
      WaveFormat.wBitsPerSample = 16;    // 16位音频 设置每个样本的位深为 16 位
      WaveFormat.nBlockAlign = (WaveFormat.nChannels * WaveFormat.wBitsPerSample) / 8;
      // 计算数据块对齐大小，公式为：nBlockAlign = nChannels * (wBitsPerSample / 8)
      // 这里除以 8 是因为每个样本的大小是按字节来计算的，nChannels 是声道数
      // wBitsPerSample 是每个样本的位数，除以 8 转换为字节
      WaveFormat.nAvgBytesPerSec =  WaveFormat.nSamplesPerSec * WaveFormat.nBlockAlign;
      // 计算每秒的平均字节数，公式为：nAvgBytesPerSec = nSamplesPerSec * nBlockAlign
      // 这表示每秒音频数据流的字节数，它帮助估算缓冲区大小
            // clang-format on

            // 函数用于设置 DirectSound 的协作等级
            if (SUCCEEDED(DirectSound->SetCooperativeLevel(window, DSSCL_PRIORITY))) {
                // 注意: 创建一个主缓冲区
                // 使用 DirectSoundCreate 函数创建一个 DirectSound
                // 对象，并初始化主缓冲区 具体的实现步骤可以根据实际需求补充
                DSBUFFERDESC BufferDescription = {};
                BufferDescription.dwSize = sizeof(BufferDescription);  // 结构的大小
                // dwFlags：设置为
                // DSBCAPS_PRIMARYBUFFER，指定我们要创建的是主缓冲区，而不是次缓冲区。
                BufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;

                LPDIRECTSOUNDBUFFER PrimaryBuffer = NULL;
                if (SUCCEEDED(DirectSound->CreateSoundBuffer(
                        &BufferDescription,  // 指向缓冲区描述结构体的指针
                        &PrimaryBuffer,      // 指向创建的缓冲区对象的指针
                        NULL                 // 外部未知接口，通常传入 NULL
                        ))) {
                    if (SUCCEEDED(PrimaryBuffer->SetFormat(&WaveFormat))) {
                        // 注意:we have finally set the format
                        OutputDebugString("SetFormat success");
                    } else {
                        // 注意:
                        OutputDebugString("SetFormat failure");
                    }
                } else {
                }

            } else {
            }
            // 注意: 创建第二个缓冲区
            // 创建次缓冲区来承载音频数据，并在播放时使用
            // 对象，并初始化主缓冲区 具体的实现步骤可以根据实际需求补充
            DSBUFFERDESC BufferDescription = {};
            BufferDescription.dwSize = sizeof(BufferDescription);  // 结构的大小
            // dwFlags：设置为
            // DSBCAPS_GETCURRENTPOSITION2 |
            // DSBCAPS_GLOBALFOCUS两个标志会使次缓冲区在播放时更加精确，同时在应用失去焦点时保持音频输出
            BufferDescription.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
            BufferDescription.dwBufferBytes = BufferSize;  // 缓冲区大小
            BufferDescription.lpwfxFormat = &WaveFormat;   // 指向音频格式的指针
            if (SUCCEEDED(DirectSound->CreateSoundBuffer(
                    &BufferDescription,      // 指向缓冲区描述结构体的指针
                    &GlobalSecondaryBuffer,  // 指向创建的缓冲区对象的指针
                    NULL                     // 外部未知接口，通常传入 NULL
                    ))) {
                OutputDebugString("SetFormat success");
            } else {
                OutputDebugString("SetFormat failure");
            }
            // 注意: 开始播放!
            // 调用相应的 DirectSound API 开始播放音频
        } else {
        }
    } else {
    }
}

// 处理并映射摇杆的输入值
internal real32 Win32ProcessXinputStickValue(SHORT Value, SHORT DeadZoneThreshold) {
    real32 Result = 0;

    // 检查当前摇杆值是否小于负的死区阈值
    if (Value < -DeadZoneThreshold) {
        // 如果摇杆值在负方向超过死区，将值映射到 -1.0 到 0 的范围
        // (摇杆值 + 死区阈值) 以死区边界为起点进行线性映射
        Result = (real32)(Value + DeadZoneThreshold) / (32768.0f - DeadZoneThreshold);
    }
    // 检查当前摇杆值是否大于正的死区阈值
    else if (Value > DeadZoneThreshold) {
        // 如果摇杆值在正方向超过死区，将值映射到 0 到 1.0 的范围
        // (摇杆值 - 死区阈值) 以死区边界为起点进行线性映射
        Result = (real32)(Value - DeadZoneThreshold) / (32767.0f - DeadZoneThreshold);
    }

    // 返回处理后的映射值，范围为 -1.0 到 1.0
    return Result;
}

// 处理单个按键的状态更新
internal void Win32ProcessKeyboardMessage(game_button_state *NewState, bool32 IsDown) {
    if (NewState->EndedDown != IsDown) {
        // 更新按钮的状态（是否按下）
        NewState->EndedDown = IsDown;  // 将按钮的状态设置为按下（IsDown 为
                                       // true）或松开（IsDown 为 false）
        // 增加按键状态变化的计数
        ++NewState->HalfTransitionCount;  // 每次按键状态变化时，半次状态转换计数增加 1
    }
}

// 处理 XInput 数字按钮状态的函数
// XInputButtonState: 当前帧的按钮状态（位掩码表示多个按钮状态）
// OldState: 上一帧的按钮状态
// ButtonBit: 要检测的具体按钮位
// NewState: 当前帧更新后的按钮状态
internal void Win32ProcessXInputDigitalButton(DWORD XInputButtonState, game_button_state *OldState,
                                              DWORD ButtonBit, game_button_state *NewState) {
    // 判断当前按钮是否处于按下状态
    NewState->EndedDown = ((XInputButtonState & ButtonBit) == ButtonBit);
    // 如果按钮的按下状态发生变化，增加过渡计数
    NewState->HalfTransitionCount = (OldState->EndedDown != NewState->EndedDown) ? 1 : 0;
}

// 这是一个现代版本的 OpenGL
int Win32OpenGLAttribs[] = {
    // clang-format off
    WGL_CONTEXT_MAJOR_VERSION_ARB,3,
    WGL_CONTEXT_MINOR_VERSION_ARB,3,
    WGL_CONTEXT_FLAGS_ARB,0//WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
#if GAME_INTERNAL
    |WGL_CONTEXT_DEBUG_BIT_ARB
#endif
    ,
    WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
    0,
    // clang-format on

};

#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9

internal void Win32SetPixelFormat(HDC WindowDC);

internal void Win32LoadWGLExtensions() {
    WNDCLASS WindowClass = {};
    WindowClass.style = 0;
    WindowClass.lpfnWndProc = DefWindowProcA;
    WindowClass.hInstance = GetModuleHandle(0);
    WindowClass.lpszClassName = "WGLLoader";
    if (RegisterClassA(&WindowClass)) {
        HWND Window =
            CreateWindowExA(0, WindowClass.lpszClassName, "game", 0, CW_DEFAULT, CW_DEFAULT,
                            CW_DEFAULT, CW_DEFAULT, 0, 0, WindowClass.hInstance, 0);
        HDC WindowDC = GetDC(Window);
        Win32SetPixelFormat(WindowDC);

        HGLRC OpenGLRC = wglCreateContext(WindowDC);
        if (wglMakeCurrent(WindowDC, OpenGLRC)) {
            wglChoosePixelFormatARB =
                (wgl_choose_pixel_format_arb *)wglGetProcAddress("wglChoosePixelFormatARB");
            wglCreateContextAttribsARB =
                (wgl_create_context_attribts_arb *)wglGetProcAddress("wglCreateContextAttribsARB");
            wglSwapIntervalEXT = (wgl_swap_interval_ext *)wglGetProcAddress("wglSwapIntervalEXT");
            wglGetExtensionsStringEXT =
                (wgl_get_extensions_string_ext *)wglGetProcAddress("wglGetExtensionsStringEXT");

            if (wglGetExtensionsStringEXT) {
                const char *Extensions = wglGetExtensionsStringEXT();
                const char *At = Extensions;
                while (*At) {
                    while (IsWhitespace(*At)) {
                        At++;
                    }
                    const char *End = At;
                    while (*End && !IsWhitespace(*End)) {
                        ++End;
                    }
                    uintptr_t Count = End - At;
                    if (0) {
                    } else if (StringsAreEqual(Count, At, "WGL_ARB_framebuffer_sRGB")) {
                        OpenGLSupportsSRGBFrameBuffer = true;
                    } else if (StringsAreEqual(Count, At, "WGL_EXT_framebuffer_sRGB")) {
                        OpenGLSupportsSRGBFrameBuffer = true;
                    }
                    At = End;
                }
            }
            wglMakeCurrent(0, 0);
        }
        wglDeleteContext(OpenGLRC);
        ReleaseDC(Window, WindowDC);
        DestroyWindow(Window);
    }
}

internal void Win32SetPixelFormat(HDC WindowDC) {
    int SuggestedPixelFormatIndex = 0;
    GLuint ExtendedPick = 0;
    if (wglChoosePixelFormatARB) {
        int IntAttribList[] = {
            // clang-format off
            WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
            WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
            WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
#if ENABLE_GAME_STREAMING 
            WGL_DOUBLE_BUFFER_ARB,GL_FALSE,
#else
            WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
#endif
            WGL_PIXEL_TYPE_ARB,WGL_TYPE_RGBA_ARB,
            WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB,GL_TRUE,
            0
            // clang-format on
        };

        if (!OpenGLSupportsSRGBFrameBuffer) {
            IntAttribList[10] = 0;
        }

        float FloatAttribList[] = {0};
        wglChoosePixelFormatARB(WindowDC, IntAttribList, FloatAttribList, 1,
                                &SuggestedPixelFormatIndex, &ExtendedPick);
    }

    if (!ExtendedPick) {
        PIXELFORMATDESCRIPTOR DesiredPixelFormat = {};
        DesiredPixelFormat.nSize = sizeof(DesiredPixelFormat);
        DesiredPixelFormat.nVersion = 1;
        DesiredPixelFormat.iPixelType = PFD_TYPE_RGBA;
        DesiredPixelFormat.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
        DesiredPixelFormat.cColorBits = 32;
        DesiredPixelFormat.cAlphaBits = 8;
        DesiredPixelFormat.iLayerType = PFD_MAIN_PLANE;

        SuggestedPixelFormatIndex = ChoosePixelFormat(WindowDC, &DesiredPixelFormat);
    }
    PIXELFORMATDESCRIPTOR SuggestedPixelFormat;
    DescribePixelFormat(WindowDC, SuggestedPixelFormatIndex, sizeof(SuggestedPixelFormat),
                        &SuggestedPixelFormat);
    SetPixelFormat(WindowDC, SuggestedPixelFormatIndex, &SuggestedPixelFormat);
}

internal HGLRC Win32InitOpenGL(HDC WindowDC) {
    //
    Win32LoadWGLExtensions();
    Win32SetPixelFormat(WindowDC);
    bool32 ModernContext = true;
    HGLRC OpenGLRC = 0;
    if (wglCreateContextAttribsARB) {
        HGLRC ShareContext = 0;
        OpenGLRC = wglCreateContextAttribsARB(WindowDC, ShareContext, Win32OpenGLAttribs);
    }
    if (!OpenGLRC) {
        ModernContext = false;
        OpenGLRC = wglCreateContext(WindowDC);
    }
    if (wglMakeCurrent(WindowDC, OpenGLRC)) {
        opengl_info Info = OpenGLInit(ModernContext, OpenGLSupportsSRGBFrameBuffer);
        if (Info.GL_ARB_framebuffer_object) {
            // clang-format off
            glBindFramebuffer = (gl_Bind_Framebuffer *)wglGetProcAddress("glBindFramebuffer");
            glDeleteFramebuffers = (gl_Delete_Framebuffers *)wglGetProcAddress("glDeleteFramebuffers");
            glGenFramebuffers = (gl_Gen_Framebuffers *)wglGetProcAddress("glGenFramebuffers");
            glFramebufferTexture2D = (gl_Framebuffer_Texture_2D *)wglGetProcAddress("glFramebufferTexture2D");
            glCheckFramebufferStatus = (gl_Check_Framebuffer_Status *)wglGetProcAddress("glCheckFramebufferStatus");
            // clang-format on
        }
        if (wglSwapIntervalEXT) {
            wglSwapIntervalEXT(1);
        }
        glGenTextures(1, &OpenGLReservedBlitTexture);
    }
    // Succcess
    return OpenGLRC;
}

internal win32_window_dimension Win32GetWindowDimension(HWND Window) {
    win32_window_dimension Result;
    RECT ClientRect;
    GetClientRect(Window, &ClientRect);
    // 计算绘制区域的宽度和高度
    Result.Height = ClientRect.bottom - ClientRect.top;
    Result.Width = ClientRect.right - ClientRect.left;
    return Result;
}

// 这个函数用于重新调整 DIB（设备独立位图）大小
internal void Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int width, int height) {
    // device independent bitmap（设备独立位图）
    // 可能的改进：先不释放，先尝试其他方法，再如果失败再释放。
    if (Buffer->Memory) {
        VirtualFree(Buffer->Memory,  // 指定要释放的内存块起始地址
                    0,  // 要释放的大小（字节），对部分释放有效，整体释放则设为 0
                    MEM_RELEASE);  // MEM_RELEASE：释放整个内存块，将内存和地址空间都归还给操作系统
    }
    // 赋值后备缓冲的宽度和高度
    Buffer->Width = width;
    Buffer->Height = height;
    Buffer->BytesPerPixel = 4;

    // 设置位图信息头（BITMAPINFOHEADER）
    Buffer->Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  // 位图头大小
    Buffer->Info.bmiHeader.biWidth = Buffer->Width;            // 设置位图的宽度
    Buffer->Info.bmiHeader.biHeight = Buffer->Height;  // 设置位图的高度（负号表示自上而下的方向）
    Buffer->Info.bmiHeader.biPlanes = 1;     // 设置颜色平面数，通常为 1
    Buffer->Info.bmiHeader.biBitCount = 32;  // 每像素的位数，这里为 32 位（即 RGBA）
    Buffer->Info.bmiHeader.biCompression = BI_RGB;  // 无压缩，直接使用 RGB 颜色模式

    Buffer->Pitch = Align16(width * Buffer->BytesPerPixel);  // 每一行的字节数

    // 创建 DIBSection（设备独立位图）并返回句柄
    int BitmapMemorySize = (Buffer->Pitch * Buffer->Height);
    Buffer->Memory = VirtualAlloc(
        0,                 // lpAddress：指定内存块的起始地址。
                           // 通常设为 NULL，由系统自动选择一个合适的地址。
        BitmapMemorySize,  // 要分配的内存大小，单位是字节。
        MEM_COMMIT,  // 分配物理内存并映射到虚拟地址。已提交的内存可以被进程实际访问和操作。
        PAGE_READWRITE  // 内存可读写
    );
}

// 这个函数用于将 DIBSection 绘制到窗口设备上下文
internal void Win32DisplayBufferInWindow(platform_work_queue *RenderQueue, HDC DeviceContext,
                                         rectangle2i DrawRegion, game_render_commands *Commands,
                                         memory_arena *TempArena, uint32 WindowWidth,
                                         uint32 WindowHeight) {
    temporary_memory Temp = BeginTemporaryMemory(TempArena);
    game_render_prep Prep = PrepForRender(Commands, TempArena);
#if 0
    if (AllResourcePresent(RenderGroup)) {
        // 将渲染组内容输出到绘制缓冲区
        RenderToOutput(TranState->HighPriorityQueue, RenderGroup, &DrawBuffer,
                       &TranState->TransientArena);
    }
#endif
    if (GlobalSoftwareRendering) {
        loaded_bitmap OutputTarget;
        OutputTarget.Memory = GlobalBackbuffer.Memory;
        OutputTarget.Width = GlobalBackbuffer.Width;
        OutputTarget.Height = GlobalBackbuffer.Height;
        OutputTarget.Pitch = GlobalBackbuffer.Pitch;
        SoftwareRenderCommands(RenderQueue, Commands, &Prep, &OutputTarget, TempArena);
        OpenGLDisplayBitmap(GlobalBackbuffer.Width, GlobalBackbuffer.Height,
                            GlobalBackbuffer.Memory, GlobalBackbuffer.Pitch, DrawRegion,
                            Commands->ClearColor, OpenGLReservedBlitTexture);
        SwapBuffers(DeviceContext);
    } else {
        BEGIN_BLOCK("OpenGLRenderCommand");
        OpenGLRenderCommands(Commands, &Prep, DrawRegion, WindowWidth, WindowHeight);
        END_BLOCK();
        BEGIN_BLOCK("SwapBuffers");
        SwapBuffers(DeviceContext);
        END_BLOCK();
    }
    EndTemporaryMemory(Temp);
}

LRESULT CALLBACK Win32FadeWindowCallback(HWND hwnd,  // 窗口句柄，表示消息来源的窗口
                                         UINT Message,  // 消息标识符，表示当前接收到的消息类型
                                         WPARAM wParam,  // 与消息相关的附加信息，取决于消息类型
                                         LPARAM lParam) {
    LRESULT Result = 0;
    switch (Message) {
        case WM_CLOSE: {
        } break;
        case WM_SETCURSOR: {
            SetCursor(0);
        } break;
        default: {
            Result = DefWindowProcA(hwnd, Message, wParam, lParam);
        } break;
    }
    return Result;
}

LRESULT CALLBACK Win32MainWindowCallback(HWND hwnd,  // 窗口句柄，表示消息来源的窗口
                                         UINT Message,  // 消息标识符，表示当前接收到的消息类型
                                         WPARAM wParam,  // 与消息相关的附加信息，取决于消息类型
                                         LPARAM LParam) {  // 与消息相关的附加信息，取决于消息类型
    LRESULT Result = 0;  // 定义一个变量来存储消息处理的结果

    switch (Message) {  // 根据消息类型进行不同的处理
        case WM_CREATE: {
            OutputDebugStringA("WM_CREATE\n");
        } break;
        case WM_SIZE: {  // 窗口大小发生变化时的消息
        } break;

        case WM_DESTROY: {  // 窗口销毁时的消息
            // TODO: 处理错误，用重建窗口
            GlobalRunning = false;
        } break;
        case WM_SYSKEYDOWN:  // 系统按键按下消息，例如 Alt 键组合。
        case WM_SYSKEYUP:    // 系统按键释放消息。
        case WM_KEYDOWN:     // 普通按键按下消息。
        case WM_KEYUP: {     // 普通按键释放消息。
            Assert(!"键盘输入通过非分发消息到达!!");
        } break;
        case WM_CLOSE: {  // 窗口关闭时的消息
            // TODO: 像用户发送消息进行处理
            GlobalRunning = false;
        } break;
        case WM_WINDOWPOSCHANGING: {
            if (GetKeyState(VK_SHIFT) & 0x8000) {
                WINDOWPOS *NewPos = (WINDOWPOS *)LParam;

                RECT WindowRect;
                RECT ClientRect;
                GetWindowRect(hwnd, &WindowRect);
                GetClientRect(hwnd, &ClientRect);

                int32 ClientWidth = (ClientRect.right - ClientRect.left);
                int32 ClientHeight = (ClientRect.bottom - ClientRect.top);
                int32 WidthAdd = ((WindowRect.right - WindowRect.left) - ClientWidth);
                int32 HeightAdd = ((WindowRect.bottom - WindowRect.top) - ClientHeight);

                int32 RenderWidth = GlobalBackbuffer.Width;
                int32 RenderHeight = GlobalBackbuffer.Height;

                // int32 SugX = NewPos->cx;
                // int32 SugY = NewPos->cy;

                int32 NewCx = (RenderWidth * (NewPos->cy - HeightAdd)) / RenderHeight;
                int32 NewCy = (RenderHeight * (NewPos->cx - WidthAdd)) / RenderWidth;

                if (AbsoluteValue((real32)(NewPos->cx - NewCx)) <
                    AbsoluteValue((real32)(NewPos->cy - NewCy))) {
                    NewPos->cx = NewCx + WidthAdd;
                } else {
                    NewPos->cy = NewCy + HeightAdd;
                }
            }

            Result = DefWindowProcA(hwnd, Message, wParam, LParam);
        } break;
        case WM_SETCURSOR: {
            if (DEBUGGlobalShowCursor) {
                Result = DefWindowProc(hwnd, Message, wParam, LParam);
            } else {
                SetCursor(0);
            }
        } break;

        case WM_ACTIVATEAPP: {  // 应用程序激活或失去焦点时的消息

#if 0  // 清理调试代码
            if (wParam == TRUE) {
                SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 255, LWA_ALPHA);
            } else {
                SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 64, LWA_ALPHA);
            }

            OutputDebugStringA("WM_ACTIVATEAPP\n");  // 输出调试信息，表示应用程序激活或失去焦点
#endif
        } break;

        case WM_PAINT: {  // 处理 WM_PAINT 消息，通常在窗口需要重新绘制时触发
            PAINTSTRUCT Paint;  // 定义一个 PAINTSTRUCT 结构体，保存绘制的信息
            // 调用 BeginPaint 开始绘制，并获取设备上下文 (HDC)，同时填充 Paint 结构体
            HDC DeviceContext = BeginPaint(hwnd, &Paint);
            (void)DeviceContext;
#if 0
            // 获取当前绘制区域的左上角坐标
            win32_window_dimension Dimension = Win32GetWindowDimension(hwnd);

            Win32DisplayBufferInWindow(DeviceContext, Dimension.Width, Dimension.Height,
                                       &RenderCommands);
#endif
            // 调用 EndPaint 结束绘制，并释放设备上下文
            EndPaint(hwnd, &Paint);
        } break;

        default: {  // 对于不处理的消息，调用默认的窗口过程
            Result = DefWindowProc(hwnd, Message, wParam, LParam);
            // 调用默认窗口过程处理消息
        } break;
    }

    return Result;  // 返回处理结果
}
internal void Win32ClearBuffer(win32_sound_output *SoundOutput) {
    VOID *Region1;      // 第一段区域指针，用于存放锁定后的首部分缓冲区地址
    DWORD Region1Size;  // 第一段区域的大小（字节数）
    VOID *Region2;  // 第二段区域指针，用于存放锁定后的剩余部分缓冲区地址
    DWORD Region2Size;  // 第二段区域的大小（字节数）
    if (SUCCEEDED(GlobalSecondaryBuffer->Lock(
            0,  // 缓冲区偏移量，指定开始锁定的字节位置
            SoundOutput->SecondaryBufferSize,  // 锁定的字节数，指定要锁定的区域大小
            &Region1,      // 输出，返回锁定区域的内存指针（第一个区域）
            &Region1Size,  // 输出，返回第一个锁定区域的实际字节数
            &Region2,  // 输出，返回第二个锁定区域的内存指针（可选，双缓冲或环形缓冲时使用）
            &Region2Size,  // 输出，返回第二个锁定区域的实际字节数
            0              // 标志，控制锁定行为（如从光标位置锁定等）
            ))) {
        int8 *DestSample = (int8 *)Region1;  // 将第一段区域指针转换为 16
                                             // 位整型指针，准备写入样本数据
        // 循环写入样本到第一段区域
        for (DWORD ByteIndex = 0; ByteIndex < Region1Size; ++ByteIndex) {
            *DestSample++ = 0;
        }
        for (DWORD ByteIndex = 0; ByteIndex < Region2Size; ++ByteIndex) {
            *DestSample++ = 0;
        }
        GlobalSecondaryBuffer->Unlock(Region1, Region1Size,  //
                                      Region2, Region2Size);
    }
}
internal void Win32FillSoundBuffer(win32_sound_output *SoundOutput, DWORD ByteToLock,
                                   DWORD BytesToWrite, game_sound_output_buffer *SourceBuffer) {
    VOID *Region1;      // 第一段区域指针，用于存放锁定后的首部分缓冲区地址
    DWORD Region1Size;  // 第一段区域的大小（字节数）
    VOID *Region2;  // 第二段区域指针，用于存放锁定后的剩余部分缓冲区地址
    DWORD Region2Size;  // 第二段区域的大小（字节数）
    if (SUCCEEDED(GlobalSecondaryBuffer->Lock(
            ByteToLock,    // 缓冲区偏移量，指定开始锁定的字节位置
            BytesToWrite,  // 锁定的字节数，指定要锁定的区域大小
            &Region1,      // 输出，返回锁定区域的内存指针（第一个区域）
            &Region1Size,  // 输出，返回第一个锁定区域的实际字节数
            &Region2,  // 输出，返回第二个锁定区域的内存指针（可选，双缓冲或环形缓冲时使用）
            &Region2Size,  // 输出，返回第二个锁定区域的实际字节数
            0              // 标志，控制锁定行为（如从光标位置锁定等）
            ))) {
        // int16 int16 int16
        // 左 右 左 右 左 右 左 右 左 右
        DWORD Region1SampleCount =
            Region1Size / SoundOutput->BytesPerSample;  // 计算第一段区域中的样本数量
        int16 *DestSample = (int16 *)Region1;           // 将第一段区域指针转换为 16
                                               // 位整型指针，准备写入样本数据
        int16 *SourceSample = SourceBuffer->Samples;
        // 循环写入样本到第一段区域
        for (DWORD SampleIndex = 0; SampleIndex < Region1SampleCount; ++SampleIndex) {
            *DestSample++ = *SourceSample++;  // 左声道
            *DestSample++ = *SourceSample++;  // 右声道
            SoundOutput->RunningSampleIndex++;
        }

        DWORD Region2SampleCount =
            Region2Size / SoundOutput->BytesPerSample;  // 计算第二段区域中的样本数量
        DestSample = (int16 *)Region2;                  // 将第二段区域指针转换为 16
                                        // 位整型指针，准备写入样本数据
        // 循环写入样本到第二段区域
        for (DWORD SampleIndex = 0; SampleIndex < Region2SampleCount; ++SampleIndex) {
            // 使用相同逻辑生成方波样本数据
            *DestSample++ = *SourceSample++;  // 左声道
            *DestSample++ = *SourceSample++;  // 右声道
            SoundOutput->RunningSampleIndex++;
        }

        // 解锁音频缓冲区，将数据提交给音频设备
        GlobalSecondaryBuffer->Unlock(Region1, Region1Size, Region2, Region2Size);
    }
}

internal void Win32BuildEXEPathFileName(win32_state *State, const char *FileName, int DestCount,
                                        char *Dest) {
    /*
    构建完整的文件路径，将 EXE 文件所在的目录路径与文件名拼接起来，结果存储在 `Dest` 中。

    参数：
    - `State`：指向 `win32_state` 结构的指针，用于访问 EXE 文件的目录路径。
    - `FileName`：需要拼接的文件名（C 风格字符串）。
    - `DestCount`：目标缓冲区 `Dest` 的大小（字节数）。
    - `Dest`：指向用于存储拼接结果的目标缓冲区。
    */

    // 调用 `CatStrings` 将 EXE 路径和文件名拼接起来。
    // 计算 EXE 路径的长度：从 `EXEFileName` 开始到 `OnePastLastEXEFileNameSlash`（不包含斜杠）。
    CatStrings(State->OnePastLastEXEFileNameSlash - State->EXEFileName, State->EXEFileName,  //
               StringLength(FileName), FileName,  // 获取文件名及其长度
               DestCount,                         // 目标缓冲区大小
               Dest);                             // 存储结果的目标缓冲区
}
internal void Win32GetInputFileLocation(win32_state *State, bool32 InputStream, int SlotIndex,
                                        int DestCount, char *Dest) {
    // 生成输入文件的完整路径并存储到目标缓冲区中

    // 定义一个临时字符串来存储文件名
    char Temp[64];

    // 使用 wsprintf 来格式化字符串，将 SlotIndex 和 InputStream 状态拼接成一个文件名
    // 文件名格式：loop_edit_<SlotIndex>_<input/state>.hmi
    wsprintf(Temp, "loop_edit_%d_%s.hmi", SlotIndex, InputStream ? "input" : "state");

    // 调用 Win32BuildEXEPathFileName 函数，将生成的文件名与 EXE 路径结合
    // 最终路径被存储到 Dest 中
    Win32BuildEXEPathFileName(State, Temp, DestCount, Dest);
}

// 定义一个函数，用于获取指定索引的重放缓冲区
internal win32_replay_buffer *Win32GetReplayBuffer(win32_state *State, unsigned int Index) {
    // 确保提供的索引在重放缓冲区数组的有效范围内
    Assert(Index < ArrayCount(State->ReplayBuffers));

    // 返回指定索引位置的重放缓冲区指针
    win32_replay_buffer *Result = &State->ReplayBuffers[Index];

    // 返回结果
    return Result;
}

// 开始录制输入
// 该函数初始化输入录制，将游戏内存的当前状态写入文件作为记录的起点。
internal void Win32BeginRecordingInput(win32_state *State, int InputRecordingIndex) {
    win32_replay_buffer *ReplayBuffer = Win32GetReplayBuffer(State, InputRecordingIndex);
    if (ReplayBuffer->MemoryBlock) {
        // 设置当前录制索引，表示正在进行录制
        State->InputRecordingIndex = InputRecordingIndex;
        State->RecordingHandle = ReplayBuffer->FileHandle;
        // 设置当前录制索引，表示正在进行录制
        State->InputRecordingIndex = InputRecordingIndex;

        char FileName[WIN32_STATE_FILE_NAME_COUNT];
        Win32GetInputFileLocation(State, true, InputRecordingIndex, sizeof(FileName), FileName);

        // 创建一个文件用于写入录制数据
        State->RecordingHandle = CreateFileA(FileName,       //
                                             GENERIC_WRITE,  // 写入权限
                                             0, 0,           //
                                             CREATE_ALWAYS,  // 如果文件存在则覆盖
                                             0, 0);

#if 0
        LARGE_INTEGER FilePosition;  // 定义一个 LARGE_INTEGER 类型的变量，用于存储文件指针的位置
        FilePosition.QuadPart = (DWORD)State->TotalSize;
        // 将 State->TotalSize 的值赋给 FilePosition.QuadPart。State->TotalSize
        // 可能是一个文件的总大小，或目标文件指针的位置。使用 (DWORD) 强制转换假设
        // TotalSize 小于 4GB。

        // 调用 SetFilePointerEx 函数设置文件指针位置
        // SetFilePointerEx 的参数依次为：
        // 1. State->RecordingHandle：文件句柄，表示要操作的文件
        // 2. FilePosition：要设置的文件指针位置，类型为 LARGE_INTEGER，表示文件中的字节偏移量
        // 3. 0：指向一个变量的指针，用来返回当前文件指针位置。在此例中不需要返回位置，传递 NULL 或
        // 0 即可
        // 4. FILE_BEGIN：表示从文件开头开始设置文件指针位置
        SetFilePointerEx(State->RecordingHandle, FilePosition, 0, FILE_BEGIN);
#endif
        // 使用 CopyMemory 函数将游戏内存块的内容复制到重放缓冲区的内存块中
        CopyMemory(ReplayBuffer->MemoryBlock,  // 是目标内存块的地址（即你想把数据复制到哪里）
                   State->GameMemoryBlock,  // 源内存块的地址（即你想从哪里复制数据）
                   State->TotalSize);       // 复制的字节数
    }
}

// 结束录制输入
// 关闭录制文件并重置录制状态。
internal void Win32EndRecordingInput(win32_state *State) {
    CloseHandle(State->RecordingHandle);  // 关闭文件句柄
    State->InputRecordingIndex = 0;       // 重置录制索引
}

// 开始播放录制的输入
// 该函数读取录制文件中的游戏内存状态并初始化播放。
internal void Win32BeginInputPlayBack(win32_state *State, int InputPlayingIndex) {
    win32_replay_buffer *ReplayBuffer = Win32GetReplayBuffer(State, InputPlayingIndex);
    if (ReplayBuffer->MemoryBlock) {
        // 设置当前播放索引，表示正在进行回放
        State->InputPlayingIndex = InputPlayingIndex;
        State->PlaybackHandle = ReplayBuffer->FileHandle;

        char FileName[WIN32_STATE_FILE_NAME_COUNT];
        Win32GetInputFileLocation(State, true, InputPlayingIndex, sizeof(FileName), FileName);

        // 打开录制文件用于读取
        State->PlaybackHandle = CreateFileA(FileName,            //
                                            GENERIC_READ,        // 读取权限
                                            FILE_SHARE_READ, 0,  //
                                            OPEN_EXISTING,       // 文件必须存在
                                            0, 0);

#if 0
        // 定义一个 LARGE_INTEGER 类型的变量，用于存储文件指针的位置
        LARGE_INTEGER FilePosition;

        // 设置文件指针的位置为 State->TotalSize（即游戏内存的总大小），
        // 将其转换为 DWORD 类型并赋值给 FilePosition.QuadPart。
        FilePosition.QuadPart = (DWORD)State->TotalSize;

        // 调用 SetFilePointerEx 设置文件指针到指定位置（即文件的开始处）。
        // 使用 FILE_BEGIN 表示从文件的起始位置开始偏移。
        SetFilePointerEx(State->PlaybackHandle, FilePosition, 0, FILE_BEGIN);
#endif
        // 使用 CopyMemory 将重放缓冲区的内存内容复制到游戏内存块中
        // 将 ReplayBuffer->MemoryBlock 中的内容复制到 State->GameMemoryBlock 中，
        // 复制的字节数为 State->TotalSize。
        CopyMemory(State->GameMemoryBlock, ReplayBuffer->MemoryBlock, State->TotalSize);
    }
}

// 结束播放录制的输入
// 关闭回放文件并重置回放状态。
internal void Win32EndInputPlayBack(win32_state *State) {
    CloseHandle(State->PlaybackHandle);  // 关闭文件句柄
    State->InputPlayingIndex = 0;        // 重置播放索引
}

// 录制单帧输入
// 该函数将每帧的输入记录到录制文件中。
internal void Win32RecordInput(win32_state *State, game_input *NewInput) {
    DWORD BytesWritten;
    WriteFile(State->RecordingHandle, NewInput,  //
              sizeof(*NewInput), &BytesWritten, 0);
}

// 播放单帧录制的输入
// 从回放文件中读取一帧输入，如果到达文件末尾则重新开始播放。
internal void Win32PlayBackInput(win32_state *State, game_input *NewInput) {
    DWORD BytesRead = 0;

    // 尝试从文件中读取一帧输入
    if (ReadFile(State->PlaybackHandle, NewInput, sizeof(*NewInput),  //
                 &BytesRead, 0)) {
        // 如果没有读取到任何字节，说明已经到达文件末尾
        if (BytesRead == 0) {
            // 注意：我们已到达流的末尾，回到起点
            int PlayingIndex = State->InputPlayingIndex;
            Win32EndInputPlayBack(State);                  // 结束当前播放
            Win32BeginInputPlayBack(State, PlayingIndex);  // 重新开始播放
        }
    }
}

// 处理并分派待处理的消息
internal void Win32ProcessPendingMessages(win32_state *State,
                                          game_controller_input *KeyboardController) {
#if !GAME_INTERNAL
    (void)State;
#endif            //! GAME_INTERNAL
    MSG Message;  // 声明一个 MSG 结构体，用于接收消息
    // 使用 PeekMessage 从消息队列中获取消息
    for (;;) {
        BOOL GotMessage = FALSE;
        {
            TIMED_BLOCK("PeekMessage");
            GotMessage = PeekMessage(
                &Message,  // 指向一个 `MSG` 结构的指针。`PeekMessage` 将在 `lpMsg`
                           // 中填入符合条件的消息内容。
                0,         // `hWnd`
                    // 为`NULL`，则检查当前线程中所有窗口的消息；如果设置为特定的窗口句柄，则只检查该窗口的消息。
                0,         // 用于设定消息类型的范围
                0,         // 用于设定消息类型的范围
                PM_REMOVE  // 将消息从消息队列中移除，类似于 `GetMessage` 的行为。
            );
        }
        if (!GotMessage) {
            break;
        }
        // 根据消息的不同类型进行处理
        switch (Message.message) {
            case WM_QUIT: {             // 退出消息
                GlobalRunning = false;  // 设置全局标志为 false，停止程序
            } break;

            // 处理键盘相关的消息
            case WM_SYSKEYDOWN:
            case WM_SYSKEYUP:
            case WM_KEYDOWN:
            case WM_KEYUP: {
                uint64 VKCode = Message.wParam;  // 获取虚拟键码
                // 判断键盘按键在前一状态时是否已按下
                bool32 WasDown = ((Message.lParam & (1 << 30)) != 0);
                // 判断键盘按键当前是否被按下
                bool32 IsDown = ((Message.lParam & (1 << 31)) == 0);
                // 如果按下了 Alt + F4，退出程序
                bool32 AltKeyWasDown = (Message.lParam & (1 << 29));

                // 如果按键的状态发生变化（即按下/松开），则处理键盘输入
                if (IsDown != WasDown) {
                    // 针对不同的按键处理对应操作
                    if (VKCode == 'W') {  // 按下 'W' 键时的处理
                        Win32ProcessKeyboardMessage(&KeyboardController->MoveUp, IsDown);
                    } else if (VKCode == 'A') {  // 按下 'A' 键时的处理
                        Win32ProcessKeyboardMessage(&KeyboardController->MoveLeft, IsDown);
                    } else if (VKCode == 'S') {  // 按下 'S' 键时的处理
                        Win32ProcessKeyboardMessage(&KeyboardController->MoveDown, IsDown);
                    } else if (VKCode == 'D') {  // 按下 'D' 键时的处理
                        Win32ProcessKeyboardMessage(&KeyboardController->MoveRight, IsDown);
                    } else if (VKCode == 'Q') {  // 按下 'Q' 键时，处理左肩按钮
                        Win32ProcessKeyboardMessage(&KeyboardController->LeftShoulder, IsDown);
                    } else if (VKCode == 'E') {  // 按下 'E' 键时，处理右肩按钮
                        Win32ProcessKeyboardMessage(&KeyboardController->RightShoulder, IsDown);
                    } else if (VKCode == VK_UP) {  // 按下上箭头时，处理上键
                        Win32ProcessKeyboardMessage(&KeyboardController->ActionUp, IsDown);
                    } else if (VKCode == VK_DOWN) {  // 按下下箭头时，处理下键
                        Win32ProcessKeyboardMessage(&KeyboardController->ActionDown, IsDown);
                    } else if (VKCode == VK_LEFT) {  // 按下左箭头时，处理左键
                        Win32ProcessKeyboardMessage(&KeyboardController->ActionLeft, IsDown);
                    } else if (VKCode == VK_RIGHT) {  // 按下右箭头时，处理右键
                        Win32ProcessKeyboardMessage(&KeyboardController->ActionRight, IsDown);
                    } else if (VKCode == VK_ESCAPE) {  // 当按下Escape键时，处理后退操作
                        Win32ProcessKeyboardMessage(&KeyboardController->Back, IsDown);
                    } else if (VKCode == VK_SPACE) {  // 当按下空格键时，处理开始操作
                        Win32ProcessKeyboardMessage(&KeyboardController->Start, IsDown);
                    }
#if GAME_INTERNAL
                    else if (VKCode == 'P') {
                        if (IsDown) {
                            // 按下P键时的处理（此处暂无特定处理）
                            GlobalPause = !GlobalPause;
                        }
                    } else if (VKCode == 'L') {  // 检测按下的键是否为字母 'L'
                        if (IsDown) {            // 判断键是否被按下
                            if (AltKeyWasDown) {
                                // 然后开始播放刚刚录制的输入
                                Win32BeginInputPlayBack(State,
                                                        1);  // 开始回放之前录制的输入
                            } else {
                                if (State->InputPlayingIndex == 0) {
                                    // 如果当前未处于播放状态（没有正在播放的输入）
                                    if (State->InputRecordingIndex == 0) {
                                        // 如果当前没有进行录制（录制索引为 0）
                                        Win32BeginRecordingInput(State, 1);
                                        // 开始录制输入，并设置录制索引为 1
                                        // 这将初始化输入录制，准备记录游戏中的操作或事件
                                    } else {
                                        // 如果已经在录制状态
                                        Win32EndRecordingInput(State);  // 结束当前录制

                                        // 然后开始播放刚刚录制的输入
                                        Win32BeginInputPlayBack(State,
                                                                1);  // 开始回放之前录制的输入
                                    }
                                } else {
                                    // 如果当前正在播放录制的输入
                                    Win32EndInputPlayBack(State);  // 停止当前的输入回放
                                }
                            }
                        }
                    }
#endif
                    if (IsDown) {
                        // 判断 Alt 键是否被按下 Alt+F4 有冲突改成F4
                        if (VKCode == VK_F4 /*&& AltKeyWasDown*/) {
                            // 如果按下的是 F4 键并且 Alt 键按下，退出程序
                            GlobalRunning = false;
                        }
                        if ((VKCode == VK_RETURN) &&
                            AltKeyWasDown) {  // 检查是否按下了 Alt + Enter 键组合
                            ToggleFullscreen(Message.hwnd);  // 调用函数切换窗口的全屏状态
                        }
                    }
                }
            } break;

            // 其他消息的处理（如鼠标、窗口消息等）
            default: {
                TranslateMessage(&Message);  // 翻译消息，如果是键盘消息需要翻译
                DispatchMessage(&Message);   // 分派消息，调用窗口过程处理消息
                break;
            }
        }
    }
}

// 获取当前的高精度计时器值
inline LARGE_INTEGER Win32GetWallClock(void) {
    LARGE_INTEGER Result;
    // 调用 Windows API QueryPerformanceCounter 来获取当前的计时器值
    QueryPerformanceCounter(&Result);
    return Result;
}

// 计算两个时间点之间经过的秒数
inline real32 Win32GetSecondsElapsed(LARGE_INTEGER Start, LARGE_INTEGER End) {
    // 计算经过的时钟周期差，转换为秒
    real32 Result = ((real32)(End.QuadPart - Start.QuadPart) / (real32)GlobalPerfCountFrequency);
    return Result;
}

internal void Win32GetEXEFileName(win32_state *state) {
    // 定义存储当前可执行文件路径的缓冲区和文件名长度变量
    DWORD SizeOfFileName = GetModuleFileName(0, state->EXEFileName,  //
                                             sizeof(state->EXEFileName));
    // 获取当前可执行文件的完整路径

    // 找到路径中的最后一个反斜杠位置，以定位文件名部分的起始点
    state->OnePastLastEXEFileNameSlash = state->EXEFileName + SizeOfFileName;
    for (char *SCan = state->EXEFileName; *SCan; ++SCan) {
        if (*SCan == '\\') {
            state->OnePastLastEXEFileNameSlash = SCan + 1;  // 更新指针到最后一个反斜杠后的位置
        }
    }
}

// 字符串项结构体，用于存储需要打印的字符串
struct string_entry {
    const char *StringToPrint;  // 要打印的字符串
};

// 平台工作队列项结构体，表示一个任务项
struct platform_work_queue_entry {
    platform_work_queue_callback *Callback;  // 回调函数，用于执行任务
    void *Data;                              // 任务数据
};

// 平台工作队列结构体，表示一个工作队列
struct platform_work_queue {
    uint32 CompletionGoal;
    uint32 volatile CompletionCount;
    uint32 volatile NextEntryToWrite;
    uint32 volatile NextEntryToRead;
    HANDLE SemaphoreHandle;                  // 信号量句柄，用于线程同步
    platform_work_queue_entry Entries[256];  // 工作队列中的任务条目
    bool32 NeedsOpenGL;
};

// 字符串条目的数组，假定用来存储多个字符串
string_entry Entries[256];

// 工作线程的回调函数，用于打印任务信息
inline PLATFORM_WORK_QUEUE_CALLBACK(DoWorkerWork) {
    (void)Queue;       // 忽略队列信息
    char Buffer[256];  // 用于存储格式化字符串的缓冲区
    wsprintf(Buffer, "Thread %u, %s\n", GetCurrentThreadId(), (char *)Data);  // 格式化字符串
    OutputDebugStringA(Buffer);  // 将字符串输出到调试控制台
}

// 处理队列中的下一个工作项
internal bool32 Win32DoNextWorkQueueEntry(platform_work_queue *Queue) {
    bool32 WeShouldSleep = false;                             // 标记是否需要休眠
    uint32 OriginalNextEntryToRead = Queue->NextEntryToRead;  // 获取当前待处理任务的索引
    uint32 NewNextEntryToRead = (OriginalNextEntryToRead + 1) % ArrayCount(Entries);

    // 如果有待处理的工作项
    if (OriginalNextEntryToRead != Queue->NextEntryToWrite) {
        // 使用互锁操作检查并更新 NextEntryToDo，确保只有一个线程能处理任务
        uint32 Index = InterlockedCompareExchange(     //
            (LONG volatile *)&Queue->NextEntryToRead,  // 操作 OriginalNextEntryToRead
            NewNextEntryToRead,                        // 将其更新为下一个待处理的任务
            OriginalNextEntryToRead);  // 只有当 NextEntryToDo 未被更新时才成功

        // 如果互锁操作成功，执行任务
        if (Index == OriginalNextEntryToRead) {
            platform_work_queue_entry Entry = Queue->Entries[Index];  // 获取当前任务项
            Entry.Callback(Queue, Entry.Data);  // 调用任务的回调函数执行任务
            InterlockedIncrement(
                (LONG volatile *)&Queue->CompletionCount);  // 完成任务后，更新已完成任务计数
        }
    } else {
        WeShouldSleep = true;  // 如果没有待处理的工作项，设置线程为休眠状态
    }

    return WeShouldSleep;  // 返回是否需要休眠
}

// 完成所有队列中的工作项
internal void Win32CompleteAllWork(platform_work_queue *Queue) {
    // 不断处理工作队列中的任务，直到所有任务都完成
    while (Queue->CompletionGoal != Queue->CompletionCount) {
        Win32DoNextWorkQueueEntry(Queue);  // 处理下一个工作项
    }

    // 所有任务完成后，重置队列计数器
    Queue->CompletionGoal = 0;
    Queue->CompletionCount = 0;
}

// 线程的回调函数
DWORD ThreadProc(LPVOID lpParameter) {
    win32_thread_startup *Thread = (win32_thread_startup *)lpParameter;
    platform_work_queue *Queue = Thread->Queue;
    uint32 TestThreadId = GetThreadID();
    Assert(TestThreadId == GetCurrentThreadId());
    for (;;) {
        // 处理工作队列中的下一个任务，如果没有任务则等待
        if (Win32DoNextWorkQueueEntry(Queue)) {
            // 如果没有任务需要处理，等待信号量，直到有任务到来
            WaitForSingleObjectEx(Queue->SemaphoreHandle, INFINITE, false);
        }
    }
}

// 向工作队列中添加一个新的任务项
internal void Win32AddEntry(platform_work_queue *Queue, platform_work_queue_callback *Callback,
                            void *Data) {
    uint32 NewNextEntryToWrite = (Queue->NextEntryToWrite + 1) % ArrayCount(Entries);
    Assert(NewNextEntryToWrite != Queue->NextEntryToRead);
    platform_work_queue_entry *Entry = Queue->Entries + Queue->NextEntryToWrite;
    Entry->Data = Data;          // 设置任务的数据
    Entry->Callback = Callback;  // 设置任务的回调函数
    ++Queue->CompletionGoal;
    _WriteBarrier();  // 保证数据写入顺序
    // _mm_sfence();     // 内存屏障，确保所有写操作完成
    Queue->NextEntryToWrite = NewNextEntryToWrite;
    ReleaseSemaphore(Queue->SemaphoreHandle, 1, 0);  // 释放信号量，唤醒一个线程
}

// 推送字符串任务到工作队列
internal void PushString(platform_work_queue *Queue, const char *String) {
    (void)Queue;   // 忽略队列参数
    (void)String;  // 忽略字符串参数
    // AddEntry(Queue, (void *)String);  // 将字符串作为任务添加到工作队列
}

global_variable debug_table GlobalDebugTable_;
debug_table *GlobalDebugTable = &GlobalDebugTable_;

internal void Win32MakeQueue(platform_work_queue *Queue, uint32 ThreadCount,
                             win32_thread_startup *Startups) {
    Queue->CompletionCount = 0;
    Queue->CompletionGoal = 0;
    Queue->NextEntryToRead = 0;
    Queue->NextEntryToWrite = 0;
    uint32 InitialCount = 0;
    HANDLE SemaphoreHandle = CreateSemaphoreExA(0,             //
                                                InitialCount,  //
                                                ThreadCount,   //
                                                0,             //
                                                0,             //
                                                SEMAPHORE_ALL_ACCESS);
    for (uint32 ThreadIndex = 0; ThreadIndex < ThreadCount; ThreadIndex++) {
        Queue->SemaphoreHandle = SemaphoreHandle;
        win32_thread_startup *Startup = Startups + ThreadIndex;
        Startup->Queue = Queue;
        DWORD ThreadId;
        HANDLE ThreadHandle = CreateThread(0,                //
                                           0,                //
                                           ThreadProc,       //
                                           (void *)Startup,  //
                                           0, &ThreadId);

        CloseHandle(ThreadHandle);
    }
}

internal PLATFORM_FILE_ERROR(Win32FileError) {
#if GAME_INTERNAL
    OutputDebugStringA("Win32 File Error:\n");
    OutputDebugStringA(Message);
    OutputDebugStringA("\n");
#else
    (void)Message;
#endif
    Handle->NoErrors = false;
}

struct win32_platform_file_group {
    HANDLE FindHandle;
    WIN32_FIND_DATAW FindData;
};

internal PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN(Win32GetAllFilesOfTypeBegin) {
    //
    platform_file_group Result = {};
    win32_platform_file_group *Win32FileGroup = (win32_platform_file_group *)VirtualAlloc(
        0, sizeof(win32_platform_file_group), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    Result.Platform = Win32FileGroup;
    const wchar_t *WildCard = L"*.*";
    switch (Type) {
        case PlatformFileType_AssetFile: {
            WildCard = L"*.hha";
        } break;
        case PlatformFileType_SaveGameFile: {
            WildCard = L"*.hhs";
        } break;
            InvalidDefaultCase;
    }
    Result.FileCount = 0;
    WIN32_FIND_DATAW FindData;
    HANDLE FindHandle = FindFirstFileW(WildCard, &FindData);
    while (FindHandle != INVALID_HANDLE_VALUE) {
        ++Result.FileCount;
        if (!FindNextFileW(FindHandle, &FindData)) {
            break;
        }
    }
    if (FindHandle != INVALID_HANDLE_VALUE) {
        FindClose(FindHandle);
    }
    Win32FileGroup->FindHandle = FindFirstFileW(WildCard, &Win32FileGroup->FindData);

    return Result;
}

internal PLATFORM_GET_ALL_FILE_OF_TYPE_END(Win32GetAllFilesOfTypeEnd) {
    win32_platform_file_group *Win32FileGroup = (win32_platform_file_group *)FileGroup->Platform;
    if (Win32FileGroup) {
        if (Win32FileGroup->FindHandle != INVALID_HANDLE_VALUE) {
            FindClose(Win32FileGroup->FindHandle);
        }
        VirtualFree(Win32FileGroup, 0, MEM_RELEASE);
    }
}

struct win32_platform_file_handle {
    HANDLE Win32Handle;
};

internal PLATFORM_OPEN_FILE(Win32OpenNextFile) {  //
    win32_platform_file_group *Win32FileGroup = (win32_platform_file_group *)FileGroup->Platform;
    platform_file_handle Result = {};
    if (Win32FileGroup->FindHandle != INVALID_HANDLE_VALUE) {
        win32_platform_file_handle *Win32Handle = (win32_platform_file_handle *)VirtualAlloc(
            0, sizeof(platform_file_handle), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
        Result.Platform = Win32Handle;
        if (Win32Handle) {
            const wchar_t *FileName = Win32FileGroup->FindData.cFileName;
            // 打开文件以进行读取
            Win32Handle->Win32Handle = CreateFileW(FileName,         // 创建文件的文件名
                                                   GENERIC_READ,     // 只读访问权限
                                                   FILE_SHARE_READ,  // 允许其他进程读取文件
                                                   0,  // 默认安全性,NULL使用默认设置
                                                   OPEN_EXISTING,  // 如果文件存在，则打开
                                                   0,              // 文件属性
                                                   0);             // 模板文件句柄
            Result.NoErrors = (Win32Handle->Win32Handle != INVALID_HANDLE_VALUE);
        }

        if (!FindNextFileW(Win32FileGroup->FindHandle, &Win32FileGroup->FindData)) {
            FindClose(Win32FileGroup->FindHandle);
            Win32FileGroup->FindHandle = INVALID_HANDLE_VALUE;
        }
    }
    return Result;
}

internal PLATFORM_READ_DATA_FROM_FILE(Win32ReadDataFromFile) {  //

    if (PlatformNoFileErrors(Source)) {
        win32_platform_file_handle *Handle = (win32_platform_file_handle *)Source->Platform;
        OVERLAPPED Overlapped = {};
        Overlapped.Offset = (uint32)((Offset >> 0) & 0xFFFFFFFF);
        Overlapped.OffsetHigh = (uint32)((Offset >> 32) & 0xFFFFFFFF);
        uint32 FileSize32 = SafeTruncateUInt64(Size);
        DWORD BytesRead;
        if (ReadFile(Handle->Win32Handle,  //
                     Dest,                 //
                     FileSize32,           // 要读取的字节数
                     &BytesRead,           // 读取的字节数
                     &Overlapped) &&
            (FileSize32 == BytesRead)) {  // 如果读取的字节数与文件大小相符
            // 注意: 文件读取成功
        } else {
#if GAME_INTERNAL
            Win32FileError(Source, "Read file failed!");
#endif  // GAME_INTERNAL
        }
    }
}

/*
internal PLATFORM_FILE_ERROR(Win32CloseFile){
    CloseHandle(FileHandle);
}
*/

PLATFORM_ALLOCATE_MEMORY(Win32AllocateMemory) {
    void *Result = VirtualAlloc(0, Size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    return Result;
}

PLATFORM_DEALLOCATE_MEMORY(Win32DeallocateMemory) {  //
    if (Memory) {
        VirtualFree(Memory, 0, MEM_RELEASE);
    }
}

internal void Win32FullRestart(const char *SourceEXE, const char *Path, const char *DestEXE,
                               const char *DeleteEXE) {
    DeleteFile(DeleteEXE);
    if (MoveFile(DestEXE, DeleteEXE)) {
        if (MoveFile(SourceEXE, DestEXE)) {
            STARTUPINFO StartupInfo = {};
            StartupInfo.cb = sizeof(StartupInfo);
            PROCESS_INFORMATION ProcessInfo = {};
            if (CreateProcess(DeleteEXE, GetCommandLine(), 0, 0, FALSE, 0, 0, Path, &StartupInfo,
                              &ProcessInfo)) {
                CloseHandle(ProcessInfo.hProcess);
            } else {
            }
            ExitProcess(0);
        }
    }
}

inline bool32 Win32TimeIsValid(FILETIME Time) {
    bool32 Result = (Time.dwLowDateTime != 0) || (Time.dwHighDateTime != 0);
    return (Result);
}
int CALLBACK WinMain(HINSTANCE hInst, [[maybe_unused]] HINSTANCE hInstPrev,  //
                     [[maybe_unused]] PSTR cmdline, [[maybe_unused]] int cmdshow) {
    DebugSetEventRecording(true);
    win32_state Win32State = {};

    LARGE_INTEGER PerfCountFrequencyResult;
    QueryPerformanceFrequency(&PerfCountFrequencyResult);
    GlobalPerfCountFrequency = PerfCountFrequencyResult.QuadPart;

    Win32GetEXEFileName(&Win32State);

    // 定义源游戏代码 DLL 文件名及其完整路径缓冲区
    char Win32EXEFullFileName[WIN32_STATE_FILE_NAME_COUNT] = {0};

    Win32BuildEXEPathFileName(&Win32State, "win32_game.exe", sizeof(Win32EXEFullFileName),
                              Win32EXEFullFileName);
    char TempWin32EXEFullFilename[WIN32_STATE_FILE_NAME_COUNT] = {0};
    // 用于存储完整路径的缓冲区
    Win32BuildEXEPathFileName(&Win32State, "win32_game_temp.exe", sizeof(TempWin32EXEFullFilename),
                              TempWin32EXEFullFilename);

    char DeleteWin32EXEFullPath[WIN32_STATE_FILE_NAME_COUNT] = {0};
    Win32BuildEXEPathFileName(&Win32State, "win32_game_old.exe", sizeof(DeleteWin32EXEFullPath),
                              DeleteWin32EXEFullPath);

    // 定义源游戏代码 DLL 文件名及其完整路径缓冲区
    char SourceGameCodeDLLFullFileName[WIN32_STATE_FILE_NAME_COUNT] = {0};

    Win32BuildEXEPathFileName(&Win32State, "game.dll", sizeof(SourceGameCodeDLLFullFileName),
                              SourceGameCodeDLLFullFileName);
    char TempGameCodeDLLFullFilename[WIN32_STATE_FILE_NAME_COUNT] = {0};
    // 用于存储完整路径的缓冲区
    Win32BuildEXEPathFileName(&Win32State, "game_temp.dll", sizeof(TempGameCodeDLLFullFilename),
                              TempGameCodeDLLFullFilename);

    char GameCodeLockFullPath[WIN32_STATE_FILE_NAME_COUNT] = {0};
    Win32BuildEXEPathFileName(&Win32State, "lock.tmp", sizeof(GameCodeLockFullPath),
                              GameCodeLockFullPath);

    // 注意: 将Windows调度器的粒度设置为1毫秒，以使我们的 `sleep()` 函数更加精细化。
    UINT DesiredSchedulerMS = 1;
    bool32 SleepIsGranular = (timeBeginPeriod(DesiredSchedulerMS) == TIMERR_NOERROR);

#if GAME_INTERNAL
    DEBUGGlobalShowCursor = true;
#endif
    Win32LoadXInput();  // 加载 XInput 库，用于处理 Xbox 控制器输入

    WNDCLASS WindowClass = {};  // 初始化窗口类结构，默认值为零
    // 使用大括号初始化，所有成员都被初始化为零（0）或 nullptr

    Win32ResizeDIBSection(&GlobalBackbuffer, 1920,
                          1080);  // 调整 DIB（设备独立位图）大小

    // 注意：1080P 显示模式为 1920x1080 -> 一半是 960x480
    // Win32ResizeDIBSection(&GlobalBackbuffer, 960,
    //                       480);  // 调整 DIB（设备独立位图）大小

    // Win32ResizeDIBSection(&GlobalBackbuffer, 1920,
    //                       1080);  // 调整 DIB（设备独立位图）大小

    // Win32ResizeDIBSection(&GlobalBackbuffer, 1279,
    //                       719);  // 调整 DIB（设备独立位图）大小

    // WindowClass.style：表示窗口类的样式。通常设置为一些 Windows
    // 窗口样式标志（例如 CS_HREDRAW, CS_VREDRAW）。
    WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    // CS_HREDRAW 当窗口的宽度发生变化时，窗口会被重绘。
    // CS_VREDRAW 当窗口的高度发生变化时，窗口会被重绘

    //  WindowClass.lpfnWndProc：指向窗口过程函数的指针，窗口过程用于处理与窗口相关的消息。
    WindowClass.lpfnWndProc = Win32MainWindowCallback;

    // WindowClass.hInstance：指定当前应用程序的实例句柄，Windows
    // 应用程序必须有一个实例句柄。
    WindowClass.hInstance = hInst;
    WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
    // WindowClass.lpszClassName：指定窗口类的名称，通常用于创建窗口时注册该类。
    WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    WindowClass.lpszClassName = "gameWindowClass";  // 类名
    // TODO：我们如何在 Windows 上可靠地查询这个？

    if (RegisterClass(&WindowClass)) {  //
        // 如果窗口类注册成功
        HWND Window = CreateWindowEx(
#if 0  // 清理调试代码
            WS_EX_TOPMOST|WS_EX_LAYERED,       // 创建窗口，使用扩展窗口风格
#else
            0,  // 创建窗口，使用扩展窗口风格
#endif
            WindowClass.lpszClassName,  // 窗口类的名称，指向已注册的窗口类
            "game",                     // 窗口标题（窗口的名称）
            WS_OVERLAPPEDWINDOW,        // 窗口样式：重叠窗口（带有菜单、边框等）
            CW_USEDEFAULT,              // 窗口的初始位置：使用默认位置（X坐标）
            CW_USEDEFAULT,              // 窗口的初始位置：使用默认位置（Y坐标）
            1204 + 40,                  // 窗口的初始宽度：使用默认宽度
            800 + 40,                   // 窗口的初始高度：使用默认高度
            0,                          // 父窗口句柄（此处无父窗口，传0）
            0,                          // 菜单句柄（此处没有菜单，传0）
            hInst,                      // 当前应用程序的实例句柄
            0                           // 额外的创建参数（此处没有传递额外参数）
        );
        // 如果窗口创建成功，Window 将保存窗口的句柄
        if (Window) {  // 检查窗口句柄是否有效，若有效则进入消息循环
            ToggleFullscreen(Window);
            HDC OpenGLDC = GetDC(Window);
            Win32InitOpenGL(OpenGLDC);
            win32_thread_startup ThreadStartup1[6] = {};
            win32_thread_startup ThreadStartup2[2] = {};
            platform_work_queue HighPriorityQueue = {};
            platform_work_queue LowPriorityQueue = {};
            ThreadStartup2[0].Queue = &HighPriorityQueue;
            ThreadStartup2[1].Queue = &LowPriorityQueue;

            Win32MakeQueue(&HighPriorityQueue, 6, ThreadStartup1);
            LowPriorityQueue.NeedsOpenGL = true;
            Win32MakeQueue(&LowPriorityQueue, 2, ThreadStartup2);

            // 定义显示器的刷新率（每秒钟刷新次数）
            real32 MonitorRefreshHz = 60;  // 显示器刷新率为 60Hz（每秒钟刷新 60 次）
            // 获取窗口的设备上下文句柄（HDC），用于查询显示器相关信息
            HDC RefrenshDC = GetDC(Window);  // 获取与指定窗口相关联的设备上下文句柄

            // 使用 GetDeviceCaps 函数查询设备的垂直刷新率（即显示器的刷新频率）
            int Win32RefreshRate = GetDeviceCaps(RefrenshDC, VREFRESH);  // 查询显示器的垂直刷新率

#if 1
            Win32RefreshRate = 60;
#endif
            // 如果获取到的刷新率大于 1 Hz（避免获取无效值），则将其存储为 MonitorRefreshHz
            if (Win32RefreshRate > 1) {
                MonitorRefreshHz = (real32)Win32RefreshRate;  // 存储显示器的刷新率（Hz）
            }

            // 定义游戏更新的频率，假设游戏更新频率为显示器刷新率的一半
            // 假设显示器刷新率为 60Hz，那么游戏更新频率为 30Hz
            real32 GameUpdateHz = (real32)MonitorRefreshHz;
            // 计算每帧的目标时间（即每一帧所需的时间，单位：秒）
            // 例如，如果游戏更新频率是 30Hz，则每帧时间为 1/30 秒
            real32 TargetSecondsPerFrame =
                1.0f / (real32)GameUpdateHz;  // 计算每帧的目标时间，单位：秒

            // 释放窗口的设备上下文句柄（清理资源）
            ReleaseDC(Window, RefrenshDC);  // 释放与指定窗口相关联的设备上下文句柄

            // 图像测试
            win32_sound_output SoundOutput = {};  // 初始化声音输出结构体
            // 音频测试
            SoundOutput.RunningSampleIndex = 0;              // 样本索引
            SoundOutput.SamplesPerSecond = 48000;            // 采样率：每秒采样48000次
            SoundOutput.BytesPerSample = sizeof(int16) * 2;  // 一个样本的大小
            SoundOutput.SecondaryBufferSize =
                SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample;  // 缓冲区大小
            // 计算音频输出的延迟样本数
            // TODO:去掉 LatencySampleCount
            SoundOutput.LatencySampleCount =
                (int)(3 * (SoundOutput.SamplesPerSecond / GameUpdateHz));
            SoundOutput.SafetyBytes = (int)((real32)(SoundOutput.SamplesPerSecond *
                                                     SoundOutput.BytesPerSample / GameUpdateHz) /
                                            (real32)3);
            uint32 MaxPossibleOverrun = 8 * 2 * sizeof(int16);

            int16 *Samples = (int16 *)VirtualAlloc(
                0, SoundOutput.SecondaryBufferSize + MaxPossibleOverrun, MEM_RESERVE | MEM_COMMIT,
                PAGE_READWRITE);  //[48000 * 2];

            Win32InitDSound(Window, SoundOutput.SamplesPerSecond,
                            SoundOutput.SecondaryBufferSize);  // 初始化 DirectSound
            Win32ClearBuffer(&SoundOutput);
            GlobalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
            GlobalRunning = true;

            memory_arena FrameTempArena;
            memory_index FrameTempArenaSize = Megabytes(64);
            InitializeArena(&FrameTempArena, FrameTempArenaSize,
                            Win32AllocateMemory(FrameTempArenaSize));

            uint32 PushBufferSize = Megabytes(64);
            void *PushBuffer =
                VirtualAlloc(0, PushBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
            LARGE_INTEGER LastCounter = Win32GetWallClock();  // 保留上次计数器的值

#if GAME_INTERNAL
            // 设置基地址为 2
            // TB（此基地址通常用于模拟大规模内存空间或防止与操作系统其他内存地址重叠）
            LPVOID BaseAddress = 0;
            // LPVOID BaseAddress =Terabytes((uint64)2);
#else
            // 设置基地址为 0
            LPVOID BaseAddress = 0;
#endif
            // 初始化游戏内存结构体
            game_memory GameMemory = {};
            GameMemory.HighPriorityQueue = &HighPriorityQueue;
            GameMemory.LowPriorityQueue = &LowPriorityQueue;
            GameMemory.PlatformAPI.AddEntry = Win32AddEntry;
            GameMemory.PlatformAPI.CompleteAllWork = Win32CompleteAllWork;
            // 设置持久存储区的大小为 256 MB
            GameMemory.PermanentStorageSize = Megabytes(256);
            // 设置临时存储区的大小为 1 GB
            GameMemory.TransientStorageSize = Gibabytes((uint64)1);
            // 计算总内存需求
            GameMemory.DebugStorageSize = Megabytes(256);
            Win32State.TotalSize = GameMemory.PermanentStorageSize +  //
                                   GameMemory.TransientStorageSize +  //
                                   GameMemory.DebugStorageSize;
            // 使用 VirtualAlloc 来分配内存，基地址是 BaseAddress，内存大小为
            // TotalSize
            // 分配的内存具有 'MEM_RESERVE | MEM_COMMIT' 属性，并且设置为可读写的内存

            Win32State.GameMemoryBlock = VirtualAlloc(BaseAddress, Win32State.TotalSize,
                                                      MEM_RESERVE | MEM_COMMIT,  //
                                                      PAGE_READWRITE);
            GameMemory.PermanentStorage = Win32State.GameMemoryBlock;
            // 设置临时存储区的起始位置在持久存储之后
            GameMemory.TransientStorage =
                (uint8 *)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize;
            GameMemory.DebugStorage =
                (uint8 *)GameMemory.TransientStorage + GameMemory.TransientStorageSize;
#if GAME_INTERNAL
            GameMemory.DebugTable = GlobalDebugTable;
#endif
            GameMemory.PlatformAPI.GetAllFilesOfTypeBegin = Win32GetAllFilesOfTypeBegin;
            GameMemory.PlatformAPI.GetAllFilesOfTypeEnd = Win32GetAllFilesOfTypeEnd;
            GameMemory.PlatformAPI.OpenNextFile = Win32OpenNextFile;
            GameMemory.PlatformAPI.ReadDataFromFile = Win32ReadDataFromFile;
            GameMemory.PlatformAPI.FileError = Win32FileError;
#if GAME_INTERNAL
            GameMemory.PlatformAPI.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory;
            GameMemory.PlatformAPI.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile;
            GameMemory.PlatformAPI.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteFileEntireFile;
            GameMemory.PlatformAPI.DEBUGPlatformExecuteSystemCommand =
                DEBUGPlatformExecuteSystemCommand;
            GameMemory.PlatformAPI.DEBUGPlatformCloseFileHandle = DEBUGPlatformCloseFileHandle;
            GameMemory.PlatformAPI.DEBUGPlatformGetProcessState = DEBUGPlatformGetProcessState;
#endif  // GAME_INTERNAL
            GameMemory.PlatformAPI.AllocateMemory = Win32AllocateMemory;
            GameMemory.PlatformAPI.DeallocateMemory = Win32DeallocateMemory;

            uint32 TextureOpCount = 1024;
            platform_texture_op_queue *TextureOpQueue = &GameMemory.TextureOpQueue;
            TextureOpQueue->FirstFree =
                (texture_op *)VirtualAlloc(0, sizeof(texture_op) * TextureOpCount,
                                           MEM_RESERVE | MEM_COMMIT,  //
                                           PAGE_READWRITE);
            for (uint32 TextureOpIndex = 0; TextureOpIndex < (TextureOpCount - 1);
                 ++TextureOpIndex) {
                texture_op *Op = TextureOpQueue->FirstFree + TextureOpIndex;
                Op->Next = TextureOpQueue->FirstFree + TextureOpIndex + 1;
            }
            // 循环遍历所有重放缓冲区
            for (uint32 ReplayIndex = 0; ReplayIndex < ArrayCount(Win32State.ReplayBuffers);
                 ++ReplayIndex) {
                // 获取当前索引对应的重放缓冲区
                win32_replay_buffer *ReplayBuffer = &Win32State.ReplayBuffers[ReplayIndex];

                // 获取输入文件的位置（将文件名存储到 ReplayFileName 中）
                // Win32GetInputFileLocation 函数生成该文件的路径和名称
                Win32GetInputFileLocation(&Win32State, false, ReplayIndex,
                                          sizeof(ReplayBuffer->ReplayFileName),
                                          ReplayBuffer->ReplayFileName);

                // 创建一个文件用于写入录制数据
                // 使用 CreateFileA 打开或创建一个文件，权限设置为可读可写
                // CREATE_ALWAYS 表示如果文件已存在则覆盖
                ReplayBuffer->FileHandle =
                    CreateFileA(ReplayBuffer->ReplayFileName,  //
                                GENERIC_WRITE | GENERIC_READ,  // 允许读写操作
                                0, 0,                          // 无共享模式
                                CREATE_ALWAYS,                 // 如果文件存在则覆盖
                                0, 0);                         // 不使用额外的属性

                // 检查文件是否成功打开
                if (ReplayBuffer->FileHandle == INVALID_HANDLE_VALUE) {
                    // 如果文件打开失败，获取并打印错误信息
                    DWORD dwError = GetLastError();
                    printf("CreateFileA failed with error code %lu\n", dwError);
                }

                // 创建文件映射对象，用于将文件映射到进程的内存中
                // 通过指定文件句柄、内存页属性、文件大小（通过 MaxSize）来创建
                LARGE_INTEGER MaxSize;
                MaxSize.QuadPart = Win32State.TotalSize;  // 设置文件映射的大小
                ReplayBuffer->MemoryMap = CreateFileMapping(ReplayBuffer->FileHandle,  //
                                                            0,               // 默认安全性
                                                            PAGE_READWRITE,  // 可读写映射
                                                            MaxSize.HighPart,  // 文件大小的高32位
                                                            MaxSize.LowPart,  // 文件大小的低32位
                                                            0);  // 不为映射指定名称

                // 检查文件映射对象是否成功创建
                if (ReplayBuffer->MemoryMap == NULL) {
                    // 如果创建失败，获取并打印错误信息
                    DWORD dwError = GetLastError();
                    printf("CreateFileMapping failed with error code %lu\n", dwError);
                }

                // 将文件映射到内存
                // 通过 MapViewOfFile 将文件映射到进程的虚拟内存中
                // 允许完全访问映射区域（FILE_MAP_ALL_ACCESS），大小为 Win32State.TotalSize
                ReplayBuffer->MemoryBlock = MapViewOfFile(
                    ReplayBuffer->MemoryMap, FILE_MAP_ALL_ACCESS, 0, 0, Win32State.TotalSize);

                // 这里没有错误检查，可以根据需要添加错误处理

                // 如果内存分配成功
                if (ReplayBuffer->MemoryBlock) {
                    // TODO：记录内存分配成功的日志
                } else {
                    // 如果内存分配失败，可以在这里添加处理代码
                    // 例如输出错误日志或执行其他错误处理操作
                }
            }
#if GAME_INTERNAL  // 清理调试代码
                   //  获取当前 CPU 时钟周期数，通常用于性能测量或时间标记
            int64 LastCycleCount = __rdtsc();
#endif  // GAME_INTERNAL
            LARGE_INTEGER FlipWallClock = Win32GetWallClock();
            // 如果有输入样本且成功分配了内存
            if (Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) {
                bool32 XBoxControllerPresent[XUSER_MAX_COUNT] = {};
                for (uint32 ControllerIndex = 0; ControllerIndex < XUSER_MAX_COUNT;
                     ++ControllerIndex) {
                    XBoxControllerPresent[ControllerIndex] = TRUE;
                }
                // 初始化输入结构体
                game_input Input[2] = {};
                // 将 NewInput 指向当前帧的输入
                game_input *NewInput = &Input[0];
                // 将 OldInput 指向上一帧的输入
                game_input *OldInput = &Input[1];

                // 传入每帧的目标时间（即每一帧所需的时间，单位：秒）
                NewInput->SecondsToAdvanceOverUpdate = TargetSecondsPerFrame;

#if GAME_INTERNAL
                // 调试时间标记索引初始化为 0
                int DebugTimeMarkerIndex = 0;

                // 初始化一个大小为 GameUpdateHz / 2 的调试时间标记数组，
                // 用于存储音频播放和写入光标的时间标记，数组大小是基于游戏更新频率的一半。
                win32_debug_time_marker DebugTimeMarkers[30] = {0};

                // TODO: 特别处理启动时的初始化逻辑
                // 这里的 TODO
                // 表示在游戏启动时可能需要做一些特殊的初始化操作，可能是与音频或其他系统组件相关。

                DWORD AudioLatencyBytes = 0;
                real32 AudioLatencySeconds = 0;
                (void)AudioLatencySeconds;
#endif
                bool32 SoundIsValid = false;

                win32_game_code GameCode = Win32LoadGameCode(SourceGameCodeDLLFullFileName,  //
                                                             TempGameCodeDLLFullFilename,    //
                                                             GameCodeLockFullPath);
                DebugSetEventRecording(GameCode.IsValid);
                ShowWindow(Window, SW_SHOW);
                while (GlobalRunning) {  // 启动一个无限循环，等待和处理消息
                    {
                        DEBUG_DATA_BLOCK("Platform/Control");
                        DEBUG_B32(GlobalPause);
                        DEBUG_B32(GlobalSoftwareRendering);
                        DEBUG_B32(Global_ShowShortGroups);
                    }
                    BEGIN_BLOCK("ExecutableRefresh");
                    GameMemory.ExecutableReloaded = false;
                    // 将当前帧的时间增量设置为每帧目标时间（即每帧应该花费的时间）
                    NewInput->dtForFrame = TargetSecondsPerFrame;
                    // 调用 Win32GetLastWriteTime 函数获取指定的游戏代码 DLL 文件的最后修改时间
                    FILETIME NewDLLWriteTime = Win32GetLastWriteTime(SourceGameCodeDLLFullFileName);
                    // 比较当前 DLL 文件的最后修改时间与之前加载的游戏代码的最后修改时间
                    // 如果文件被修改（时间不同），则重新加载游戏代码

                    END_BLOCK();

                    // BEGIN_BLOCK("InputProcessing");
                    // 准备绘制缓冲区，传递到游戏更新和渲染函数中
                    win32_window_dimension Dimension = Win32GetWindowDimension(Window);
                    // fit
                    // GlobalBackbuffer.Width = Dimension.Width;
                    // GlobalBackbuffer.Height = Dimension.Height;
                    game_render_commands RenderCommands =
                        RenderCommandStruct(PushBufferSize, PushBuffer, GlobalBackbuffer.Width,
                                            GlobalBackbuffer.Height);
                    rectangle2i DrawRegion =
                        AspectRatioFit(RenderCommands.Width, RenderCommands.Height, Dimension.Width,
                                       Dimension.Height);

                    game_controller_input *OldKeyboardController = GetController(OldInput, 0);
                    game_controller_input *NewKeyboardController = GetController(NewInput, 0);
                    // TODO: 我们不能把所有东西都置零，因为上下状态会不正确！！！
                    game_controller_input ZeroController = {};
                    NewKeyboardController->IsConnected = true;
                    *NewKeyboardController = ZeroController;
                    for (uint32 ButtonIndex = 0;
                         ButtonIndex < ArrayCount(NewKeyboardController->Buttons); ++ButtonIndex) {
                        NewKeyboardController->Buttons[ButtonIndex].EndedDown =
                            OldKeyboardController->Buttons[ButtonIndex].EndedDown;
                    }
                    {
                        TIMED_BLOCK("Win32 Message process");
                        Win32ProcessPendingMessages(&Win32State, NewKeyboardController);
                    }
                    {
                        TIMED_BLOCK("Mouse Position");
                        POINT MouseP;
                        // 定义一个 POINT 结构体变量
                        // MouseP，用于存储鼠标的当前屏幕坐标。

                        GetCursorPos(&MouseP);
                        // 调用 GetCursorPos
                        // 函数获取当前鼠标光标的位置，并将结果存储在 MouseP 中。
                        // 该函数返回鼠标光标相对于屏幕左上角的位置，存储在 POINT
                        // 结构体的 x 和 y 成员中。

                        // 将屏幕坐标 (MouseP.x, MouseP.y) 转换为指定窗口 (Window) 的客户区坐标
                        ScreenToClient(Window, &MouseP);

                        real32 MouseX = (real32)MouseP.x;
                        // 将鼠标的 X 坐标（屏幕上的水平位置）赋值给 NewInput->MouseX
                        // 。 这样可以在游戏中使用鼠标的 X 坐标。

                        real32 MouseY = ((real32)Dimension.Height - 1) - MouseP.y;
                        NewInput->MouseX =
                            RenderCommands.Width * ClampMapToRange((real32)DrawRegion.MinX, MouseX,
                                                                   (real32)DrawRegion.MaxX);
                        NewInput->MouseY =
                            RenderCommands.Height * ClampMapToRange((real32)DrawRegion.MinY, MouseY,
                                                                    (real32)DrawRegion.MaxY);
                        NewInput->MouseZ = 0;
                        NewInput->ShiftDown = (GetKeyState(VK_SHIFT) & (1 << 15));
                        NewInput->AltDown = (GetKeyState(VK_MENU) & (1 << 15));
                        NewInput->ControlDown = (GetKeyState(VK_CONTROL) & (1 << 15));
                    }
                    {
                        TIMED_BLOCK("Keyboard Processing");
                        // 将鼠标的 Y 坐标（屏幕上的垂直位置）赋值给 NewInput->MouseY
                        // 。 这样可以在游戏中使用鼠标的 Y 坐标。
                        DWORD WinButtonID[PlatformMouseButton_Count] = {

                            VK_LBUTTON, VK_MBUTTON, VK_RBUTTON, VK_XBUTTON1, VK_XBUTTON2,

                        };
                        for (uint32 ButtonIndex = 0; ButtonIndex < PlatformMouseButton_Count;
                             ++ButtonIndex) {
                            NewInput->MouseButtons[ButtonIndex] =
                                OldInput->MouseButtons[ButtonIndex];
                            NewInput->MouseButtons[ButtonIndex].HalfTransitionCount = 0;
                            Win32ProcessKeyboardMessage(
                                &NewInput->MouseButtons[ButtonIndex],
                                GetKeyState(WinButtonID[ButtonIndex]) & (1 << 15));
                        }
                    }
                    {
                        TIMED_BLOCK("XBox Controller");
                        // 处理鼠标左键的按下和释放事件，GetKeyState(VK_LBUTTON)
                        // 返回鼠标左键的状态 使用 & (1 << 15) 检查高位是否为
                        // 1，表示鼠标左键是否按下
                        Win32ProcessKeyboardMessage(
                            &NewInput->MouseButtons[PlatformMouseButton_Left],
                            GetKeyState(VK_LBUTTON) & (1 << 15));

                        // 处理鼠标中键的按下和释放事件，GetKeyState(VK_MBUTTON)
                        // 返回鼠标中键的状态 使用 & (1 << 15) 检查高位是否为
                        // 1，表示鼠标中键是否按下
                        Win32ProcessKeyboardMessage(
                            &NewInput->MouseButtons[PlatformMouseButton_Middle],
                            GetKeyState(VK_MBUTTON) & (1 << 15));

                        // 处理鼠标右键的按下和释放事件，GetKeyState(VK_RBUTTON)
                        // 返回鼠标右键的状态 使用 & (1 << 15) 检查高位是否为
                        // 1，表示鼠标右键是否按下
                        Win32ProcessKeyboardMessage(
                            &NewInput->MouseButtons[PlatformMouseButton_Right],
                            GetKeyState(VK_RBUTTON) & (1 << 15));

                        // 处理鼠标第一个扩展按钮（XButton1）的按下和释放事件，GetKeyState(VK_XBUTTON1)
                        // 返回按钮状态 使用 & (1 << 15) 检查高位是否为 1，表示 XButton1
                        // 是否按下
                        Win32ProcessKeyboardMessage(
                            &NewInput->MouseButtons[PlatformMouseButton_Extended0],
                            GetKeyState(VK_XBUTTON1) & (1 << 15));

                        // 处理鼠标第二个扩展按钮（XButton2）的按下和释放事件，GetKeyState(VK_XBUTTON2)
                        // 返回按钮状态 使用 & (1 << 15) 检查高位是否为 1，表示 XButton2
                        // 是否按下
                        Win32ProcessKeyboardMessage(
                            &NewInput->MouseButtons[PlatformMouseButton_Extended1],
                            GetKeyState(VK_XBUTTON2) & (1 << 15));

                        NewInput->MouseZ = 0;
                        // 设置 MouseZ 为
                        // 0，表示当前鼠标滚轮没有滚动。通常，如果鼠标滚轮没有动作，Z
                        // 值可以设置为 0。

                        // TODO: 我们应该频繁的轮询吗
                        // 需要避免轮询已断开连接的控制器，以避免在旧版库中造成 XInput
                        // 帧延迟。
                        uint64 MaxControllerCount = XUSER_INDEX_ANY;
                        if (MaxControllerCount > ArrayCount(NewInput->Controllers) - 1) {
                            MaxControllerCount = ArrayCount(NewInput->Controllers) - 1;
                        }
                        for (DWORD ControllerIndex = 0; ControllerIndex < MaxControllerCount;
                             ControllerIndex++) {
                            DWORD OurControllerIndex = ControllerIndex + 1;
                            game_controller_input *OldController =
                                GetController(OldInput, OurControllerIndex);
                            game_controller_input *NewController =
                                GetController(NewInput, OurControllerIndex);
                            // 定义一个 XINPUT_STATE 结构体，用来存储控制器的状态
                            XINPUT_STATE ControllerState;
                            // 调用 XInputGetState 获取控制器的状态
                            if (XBoxControllerPresent[ControllerIndex] &&
                                XInputGetState(ControllerIndex, &ControllerState) ==
                                    ERROR_SUCCESS) {
                                NewController->IsConnected = true;
                                // 如果获取控制器状态成功，提取 Gamepad 的数据
                                // 注意:
                                // 获取方向键的按键状态
                                // 获取当前控制器的 Gamepad 状态
                                XINPUT_GAMEPAD *Pad = &ControllerState.Gamepad;

                                // 判断方向键的按键状态
                                bool Up = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP);
                                bool Down = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
                                bool Left = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
                                bool Right = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);

                                // 输出方向键状态
                                std::cout << " Up = " << Up << " Down = " << Down
                                          << " Right = " << Right << " Left = " << Left
                                          << std::endl;

                                // 将新控制器的摇杆位置设置为基于旧控制器的状态
                                NewController->StickAverageX = Win32ProcessXinputStickValue(
                                    Pad->sThumbLX,  //
                                    XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
                                NewController->StickAverageY = Win32ProcessXinputStickValue(
                                    Pad->sThumbLY,  //
                                    XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);

                                // 输出新控制器的摇杆平均值
                                std::cout << NewController->StickAverageX
                                          << NewController->StickAverageY << std::endl;
                                if ((NewController->StickAverageX != 0.0f) ||
                                    (NewController->StickAverageY != 0.0f)) {
                                    // 设置新控制器为模拟模式
                                    NewController->IsAnalog = true;
                                }

                                // 如果按下方向键，则根据方向修改摇杆的 X 或 Y 坐标值
                                // 检测 D-Pad（方向键）向上按钮是否被按下
                                if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP) {
                                    NewController->StickAverageY =
                                        1.0f;  // 将摇杆的 Y 轴设为最大值（向上）
                                    NewController->IsAnalog = false;  // 设置控制器为非模拟模式
                                }

                                // 检测 D-Pad（方向键）向下按钮是否被按下
                                if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {
                                    NewController->StickAverageY =
                                        -1.0f;  // 将摇杆的 Y 轴设为最小值（向下）
                                    NewController->IsAnalog = false;  // 设置控制器为非模拟模式
                                }

                                // 检测 D-Pad（方向键）向左按钮是否被按下
                                if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {
                                    NewController->StickAverageX =
                                        1.0f;  // 将摇杆的 X 轴设为最大值（向左）
                                    NewController->IsAnalog = false;  // 设置控制器为非模拟模式
                                }

                                // 检测 D-Pad（方向键）向右按钮是否被按下
                                if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {
                                    NewController->StickAverageX =
                                        -1.0f;  // 将摇杆的 X 轴设为最小值（向右）
                                    NewController->IsAnalog = false;  // 设置控制器为非模拟模式
                                }

                                // 设置阈值用于处理摇杆偏移
                                real32 Threshold = 0.5f;

                                // 根据摇杆的 X 坐标值触发左右移动
                                Win32ProcessXInputDigitalButton(
                                    (NewController->StickAverageX < -Threshold) ? 1 : 0,  //
                                    &OldController->MoveLeft,                             // 左移
                                    1,                                                    //
                                    &NewController->MoveLeft);

                                Win32ProcessXInputDigitalButton(
                                    (NewController->StickAverageX > Threshold) ? 1 : 0,  //
                                    &OldController->MoveRight,                           // 右移
                                    1,                                                   //
                                    &NewController->MoveRight);

                                // 根据摇杆的 Y 坐标值触发上下移动
                                Win32ProcessXInputDigitalButton(
                                    (NewController->StickAverageY < -Threshold) ? 1 : 0,  //
                                    &OldController->MoveDown,                             // 下移
                                    1,                                                    //
                                    &NewController->MoveDown);

                                Win32ProcessXInputDigitalButton(
                                    (NewController->StickAverageY > Threshold) ? 1 : 0,  //
                                    &OldController->MoveUp,                              // 上移
                                    1,                                                   //
                                    &NewController->MoveUp);

                                // 处理 A 按钮的数字输入
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,               // 获取当前帧的按钮状态
                                    &OldController->ActionDown,  // 传入上一帧的 A 按钮状态
                                    XINPUT_GAMEPAD_A,  // A 按钮的位掩码，用于判断 A
                                                       // 按钮是否被按下
                                    &NewController->ActionDown);  // 更新新控制器中的 A 按钮状态

                                // 处理 B 按钮的数字输入
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,                // 获取当前帧的按钮状态
                                    &OldController->ActionRight,  // 传入上一帧的 B 按钮状态
                                    XINPUT_GAMEPAD_B,  // B 按钮的位掩码，用于判断 B
                                                       // 按钮是否被按下
                                    &NewController->ActionRight);  // 更新新控制器中的 B 按钮状态

                                // 处理 X 按钮的数字输入
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,               // 获取当前帧的按钮状态
                                    &OldController->ActionLeft,  // 传入上一帧的 X 按钮状态
                                    XINPUT_GAMEPAD_X,  // X 按钮的位掩码，用于判断 X
                                                       // 按钮是否被按下
                                    &NewController->ActionLeft);  // 更新新控制器中的 X 按钮状态

                                // 处理左肩按钮的数字输入
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,                 // 获取当前帧的按钮状态
                                    &OldController->LeftShoulder,  // 传入上一帧的左肩按钮状态
                                    XINPUT_GAMEPAD_LEFT_SHOULDER,  // 左肩按钮的位掩码，用于判断左肩按钮是否被按下
                                    &NewController->LeftShoulder);  // 更新新控制器中的左肩按钮状态

                                // 处理右肩按钮的数字输入
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,  // 获取当前帧的按钮状态
                                    &OldController->RightShoulder,  // 传入上一帧的右肩按钮状态
                                    XINPUT_GAMEPAD_RIGHT_SHOULDER,  // 右肩按钮的位掩码，用于判断右肩按钮是否被按下
                                    &NewController->RightShoulder);  // 更新新控制器中的右肩按钮状态

                                // 处理 Start 按钮的状态
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,           // 获取当前控制器的按钮状态
                                    &OldController->Start,   // 传入旧控制器的状态
                                    XINPUT_GAMEPAD_START,    // 按钮类型：Start 按钮
                                    &NewController->Start);  // 更新新控制器的状态

                                // 处理 Back 按钮的状态
                                Win32ProcessXInputDigitalButton(
                                    Pad->wButtons,          // 获取当前控制器的按钮状态
                                    &OldController->Back,   // 传入旧控制器的状态
                                    XINPUT_GAMEPAD_BACK,    // 按钮类型：Back 按钮
                                    &NewController->Back);  // 更新新控制器的状态

                            } else {
                                NewKeyboardController->IsConnected = false;
                                XBoxControllerPresent[ControllerIndex] = false;
                            }
                        }
                    }

                    // END_BLOCK();

                    BEGIN_BLOCK("GameUpdate");
                    /*
                    这是声音输出计算的工作原理：
                    -
                    我们定义一个安全值（`SafetyBytes`），表示游戏更新循环可能会变化的样本数量（假设最多2毫秒）。
                    - 写入音频时，我们根据播放光标的位置，预测下一个帧边界时播放光标的位置。
                    - 判断写入光标是否在预测目标位置之前（加上安全范围）。
                    - 如果是，则目标填充位置是预测的帧边界加上一个完整的帧长度。
                    -
                    如果写入光标已经超过目标位置，则假设无法完美同步音频，这种情况下会写入一帧的音频数据，并加上安全值保护样本。
                    - 目标是低延迟情况下实现音频同步，但在高延迟情况下保证不会出现声音中断。
                    */

                    game_offscreen_buffer Buffer = {};
                    Buffer.Memory = GlobalBackbuffer.Memory;
                    Buffer.Width = GlobalBackbuffer.Width;
                    Buffer.Height = GlobalBackbuffer.Height;
                    Buffer.Pitch = GlobalBackbuffer.Pitch;

                    if (!GlobalPause) {
                        if (Win32State.InputRecordingIndex) {
                            // 如果当前处于录制状态（InputRecordingIndex 不为 0）
                            Win32RecordInput(&Win32State, NewInput);
                            // 调用函数将当前帧的输入记录下来
                        }

                        if (Win32State.InputPlayingIndex) {
                            game_input Temp = *NewInput;
                            // 如果当前处于回放状态（InputPlayingIndex 不为 0）
                            Win32PlayBackInput(&Win32State, NewInput);
                            // 调用函数将回放的输入加载到当前帧的输入中
                            for (uint32 MouseButtonIndex = 0;
                                 MouseButtonIndex < PlatformMouseButton_Count; ++MouseButtonIndex) {
                                NewInput->MouseButtons[MouseButtonIndex] =
                                    Temp.MouseButtons[MouseButtonIndex];
                            }
                            NewInput->MouseX = Temp.MouseX;
                            NewInput->MouseY = Temp.MouseY;
                            NewInput->MouseZ = Temp.MouseZ;
                        }

                        if (GameCode.UpdateAndRender) {
                            // 调用游戏的更新和渲染逻辑，填充缓冲区
                            GameCode.UpdateAndRender(&GameMemory, NewInput, &RenderCommands);
                            // HandleDebugCycleCounters(&GameMemory);
                            if (Input->QuitRequested) {
                                GlobalRunning = false;
                            }
                        }
                    }
                    END_BLOCK();
                    BEGIN_BLOCK("AudioUpdate");
                    if (!GlobalPause) {
                        // 声音处理部分

                        // 声明两个变量，分别表示音频缓冲区的播放光标和写入光标
                        DWORD PlayCursor;  // 播放光标：当前音频硬件正在播放的位置
                        DWORD WriteCursor;  // 写入光标：硬件允许写入新音频数据的位置

                        // 获取当前时间点，作为当前帧结束的时间
                        LARGE_INTEGER AudioWallClock = Win32GetWallClock();

                        // 计算当前帧的时长（以毫秒为单位）
                        real32 FromBeginToAudioSeconds =
                            Win32GetSecondsElapsed(FlipWallClock, AudioWallClock);

                        // 获取音频缓冲区的当前播放位置和写入位置
                        if (GlobalSecondaryBuffer->GetCurrentPosition(&PlayCursor, &WriteCursor) ==
                            DS_OK) {
                            // 如果成功获取了音频缓冲区的当前位置
                            if (!SoundIsValid) {
                                /*
                                    如果声音状态无效（例如程序刚启动或是首次运行音频逻辑）：
                                    - 使用写入光标的当前位置作为基准，初始化运行样本索引。
                                    -
                                   将写入光标的位置除以每个样本的字节数，以确定对应的样本索引。
                                */
                                SoundOutput.RunningSampleIndex =
                                    WriteCursor / SoundOutput.BytesPerSample;
                                SoundIsValid = true;  // 设置声音状态为有效
                            }

                            DWORD TargetCursor = 0;  // 目标写入位置
                            DWORD BytesToWrite = 0;  // 需要写入的字节数

                            // 计算需要锁定的字节位置，基于当前运行的样本索引
                            DWORD ByteToLock =
                                ((SoundOutput.RunningSampleIndex * SoundOutput.BytesPerSample) %
                                 SoundOutput.SecondaryBufferSize);

                            // 计算每帧需要的字节数（基于采样率和帧率）
                            DWORD ExpectedSoundBytesPerFrame =
                                (DWORD)((SoundOutput.SamplesPerSecond *
                                         SoundOutput.BytesPerSample) /
                                        GameUpdateHz);
                            // 计算距离下一个翻转（flip）操作剩余的时间，以秒为单位
                            real32 SecondsLeftUntilFlip =
                                (TargetSecondsPerFrame - FromBeginToAudioSeconds);

                            // 计算从当前时刻到下一个翻转操作之间，预计需要处理的音频字节数
                            // TargetSecondsPerFrame 表示每帧的目标时间，
                            // FromBeginToAudioSeconds 表示从开始到当前时刻的音频时间，
                            // ExpectedSoundBytesPerFrame 是每帧预期的音频字节数。
                            // SecondsLeftUntilFlip 是剩余的时间，通过比例计算剩余字节数。
                            [[maybe_unused]] DWORD ExpectedBytesUntilFlip =
                                (DWORD)((SecondsLeftUntilFlip / TargetSecondsPerFrame) *
                                        (real32)ExpectedSoundBytesPerFrame);

                            // 预测当前帧边界时的播放光标位置
                            DWORD ExpectedFrameBoundaryByte =
                                PlayCursor + ExpectedSoundBytesPerFrame;

                            // 确保写入光标位置是安全的（考虑缓冲区环绕）
                            DWORD SafeWriteCursor = WriteCursor;
                            if (SafeWriteCursor < PlayCursor) {
                                SafeWriteCursor +=
                                    SoundOutput
                                        .SecondaryBufferSize;  // 修正光标位置以防止缓冲区回绕
                            }
                            Assert(SafeWriteCursor >= PlayCursor);

                            SafeWriteCursor += SoundOutput.SafetyBytes;  // 加入安全保护字节范围

                            // 判断音频卡的延迟是否足够低
                            bool32 AudioCardIsLowLatency =
                                (SafeWriteCursor < ExpectedFrameBoundaryByte);

                            if (AudioCardIsLowLatency) {
                                /*
                                    如果音频卡延迟较低：
                                    - 将目标写入光标设置为下一帧边界加上一个完整的帧长度。
                                */
                                TargetCursor =
                                    ExpectedFrameBoundaryByte + ExpectedSoundBytesPerFrame;
                            } else {
                                /*
                                    如果音频卡延迟较高：
                                    -
                                   将目标写入光标设置为写入光标位置，加上一个帧长度和安全字节数。
                                */
                                TargetCursor = WriteCursor + ExpectedSoundBytesPerFrame +
                                               SoundOutput.SafetyBytes;
                            }

                            // 确保目标光标位置在环绕缓冲区内
                            TargetCursor = TargetCursor % SoundOutput.SecondaryBufferSize;

                            // 计算需要写入的字节数
                            if (ByteToLock > TargetCursor) {
                                /*
                                    如果锁定位置在目标位置之后：
                                    -
                                   写入从锁定位置到缓冲区末尾的字节数，再加上从缓冲区开头到目标位置的字节数。
                                */
                                BytesToWrite =
                                    (SoundOutput.SecondaryBufferSize - ByteToLock) + TargetCursor;
                            } else {
                                /*
                                    如果锁定位置在目标位置之前：
                                    - 写入从锁定位置到目标位置之间的字节数。
                                */
                                BytesToWrite = TargetCursor - ByteToLock;
                            }

                            // 设置音频缓冲区结构
                            game_sound_output_buffer SoundBuffer = {};
                            SoundBuffer.SamplesPerSecond =
                                SoundOutput.SamplesPerSecond;  // 每秒采样数
                            SoundBuffer.SampleCount = Align8(
                                BytesToWrite / SoundOutput.BytesPerSample);  // 需要写入的样本数
                            BytesToWrite = SoundBuffer.SampleCount * SoundOutput.BytesPerSample;
                            SoundBuffer.Samples = Samples;  // 指向样本数据的指针

                            if (GameCode.GetSoundSamples) {
                                // 调用游戏逻辑获取需要填充的声音样本数据
                                GameCode.GetSoundSamples(&GameMemory, &SoundBuffer);
                            }

#if GAME_INTERNAL
                            // DWORD TestPlayCursor;
                            // DWORD TestWriteCursor;
                            // GlobalSecondaryBuffer->GetCurrentPosition(&TestPlayCursor, //
                            //                                           &TestWriteCursor);

                            win32_debug_time_marker *Marker =
                                &DebugTimeMarkers[DebugTimeMarkerIndex];
                            Marker->OutputPlayCursor = PlayCursor;
                            Marker->OutputWriteCursor = WriteCursor;
                            Marker->OutputByteCount = BytesToWrite;
                            Marker->OutputLocation = ByteToLock;
                            Marker->ExpectedFlipCursor = ExpectedFrameBoundaryByte;
                            // 定义未封装的写指针，用于计算逻辑上的写指针位置
                            DWORD UnwrappedWriteCursor = WriteCursor;

                            // 如果写指针在播放指针之前（循环缓冲区重绕的情况），
                            // 则将写指针逻辑上移到缓冲区的后面，以便计算差值
                            if (UnwrappedWriteCursor < PlayCursor) {
                                UnwrappedWriteCursor += SoundOutput.SecondaryBufferSize;
                            }

                            // 计算写指针和播放指针之间的字节数，
                            // 这表示写指针和播放指针的距离，可以用来确定可写区域大小。
                            // 注意：由于WriteCursor可能已经逻辑上被"展开"，直接相减是安全的
                            AudioLatencyBytes = UnwrappedWriteCursor - PlayCursor;

                            AudioLatencySeconds =
                                ((real32)AudioLatencyBytes / (real32)SoundOutput.BytesPerSample) /
                                (real32)SoundOutput.SamplesPerSecond;

#endif
                            Win32FillSoundBuffer(&SoundOutput, ByteToLock, BytesToWrite,
                                                 &SoundBuffer);
                            // 计算需要锁定的字节位置，基于当前样本索引和每样本字节数
                        } else {
                            SoundIsValid = false;
                        }
                    }
                    END_BLOCK();

#if GAME_INTERNAL
                    BEGIN_BLOCK("DebugCollation");

                    GameMemory.ExecutableReloaded = false;
                    bool32 ExecutableNeedsToBeReloaded =
                        CompareFileTime(&NewDLLWriteTime, &GameCode.DLLLastWriteTime);
#if 0
                    FILETIME NewExeWriteTime = Win32GetLastWriteTime(Win32EXEFullFileName);
                    FILETIME OldExeWriteTime = Win32GetLastWriteTime(TempWin32EXEFullFilename);

                    if (Win32TimeIsValid(OldExeWriteTime)) {
                        bool32 Win32NeedsToReload =
                            (CompareFileTime(&NewExeWriteTime, &OldExeWriteTime) != 0);
                        if (Win32NeedsToReload) {
                            char path[WIN32_STATE_FILE_NAME_COUNT] = {0};
                            Win32BuildEXEPathFileName(&Win32State, "", sizeof(path), path);
                            Win32FullRestart(TempWin32EXEFullFilename, path, Win32EXEFullFileName,
                                             DeleteWin32EXEFullPath);
                        }
                    }
#endif
                    if (ExecutableNeedsToBeReloaded) {
                        Win32CompleteAllWork(&HighPriorityQueue);
                        Win32CompleteAllWork(&LowPriorityQueue);
                        DebugSetEventRecording(false);
                    }

                    if (GameCode.DEBUGGameFrameEnd) {
                        GameCode.DEBUGGameFrameEnd(&GameMemory, NewInput, &RenderCommands);
                    } else {
                        GlobalDebugTable_.EventArrayIndex_EventIndex = 0;
                    }

                    if (ExecutableNeedsToBeReloaded) {
                        // 卸载当前加载的游戏代码
                        win32UnloadGameCode(&GameCode);
                        for (uint32 LoadTryIndex = 0; !GameCode.IsValid && LoadTryIndex < 100;
                             ++LoadTryIndex) {
                            // 使用 Win32LoadGameCode 函数重新加载 DLL 文件，并返回包含 DLL
                            // 句柄、函数指针等的结构体
                            GameCode = Win32LoadGameCode(SourceGameCodeDLLFullFileName,
                                                         TempGameCodeDLLFullFilename,  //
                                                         GameCodeLockFullPath);
                            Sleep(100);
                        }
                        GameMemory.ExecutableReloaded = false;
                        DebugSetEventRecording(false);
                    }
                    END_BLOCK();
#endif  // GAME_INTERNAL
                    (void)SleepIsGranular;
#if 0
                    BEGIN_BLOCK("FramerateWait");

                    if (!GlobalPause) {
                        // 获取当前时间作为工作结束的时间点
                        LARGE_INTEGER WorkCounter = Win32GetWallClock();

                        // 计算从上一帧到当前帧实际经过的时间
                        real32 WorkSecondsElapsed =
                            Win32GetSecondsElapsed(LastCounter, WorkCounter);

                        real32 SecondsElapsedForFrame = WorkSecondsElapsed;

                        // 如果当前帧消耗的时间少于目标帧时间（目标帧时间由目标帧率决定），则需要等待
                        if (SecondsElapsedForFrame < TargetSecondsPerFrame) {
                            // 如果系统的睡眠粒度已被设置为足够小（如 1 毫秒）
                            if (SleepIsGranular) {
                                // 计算还需要等待的时间，并将其转换为毫秒
                                DWORD SleepMS = (DWORD)(1000.0f * (TargetSecondsPerFrame -
                                                                   SecondsElapsedForFrame));
                                // 调用 Sleep 函数让线程休眠，以节省 CPU 资源
                                // std::cout << "Sleep " << SleepMS << " ms" << std::endl;
                                if (SleepMS > 0) {
                                    Sleep(SleepMS);
                                }
                            }
                            while (SecondsElapsedForFrame < TargetSecondsPerFrame) {
                                // 重新计算从上一帧到当前帧实际经过的时间
                                SecondsElapsedForFrame =
                                    Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());
                            }
                        } else {
                            // TODO:
                            // 丢失帧率（当前帧消耗的时间超过了目标帧时间，可能需要记录或调整以优化性能）
                            // TODO:
                            // 写日志（可以将帧率丢失的原因记录到日志文件中，便于后续分析）
                        }
                    }
                    END_BLOCK();
#endif
                    BEGIN_BLOCK("FrameDisplay");
                    BeginTicketMutex(&TextureOpQueue->Mutex);
                    texture_op *FirstTextureOp = TextureOpQueue->First;
                    texture_op *LastTextureOp = TextureOpQueue->Last;
                    TextureOpQueue->First = TextureOpQueue->Last = 0;
                    EndTicketMutex(&TextureOpQueue->Mutex);
                    if (FirstTextureOp) {
                        OpenGLManageTexture(FirstTextureOp);
                        BeginTicketMutex(&TextureOpQueue->Mutex);
                        LastTextureOp->Next = TextureOpQueue->FirstFree;
                        TextureOpQueue->FirstFree = FirstTextureOp;
                        EndTicketMutex(&TextureOpQueue->Mutex);
                    }
                    // 这个地方需要渲染一下不然是黑屏a
                    {
                        HDC DeviceContext = GetDC(Window);

                        RECT WindowRect;
                        GetClientRect(Window, &WindowRect);
#if GAME_INTERNAL
#if 0  // 清理调试代码
       //  在调试模式下同步显示音频缓冲区状态
                            Win32DebugSyncDisplay(
                                &GlobalBackbuffer,  // 传入全局后备缓冲区，用于显示
                                ArrayCount(DebugTimeMarkers),  // 传入调试时间标记的数量
                                DebugTimeMarkers,              // 传入调试时间标记数组
                                DebugTimeMarkerIndex + 1,
                                &SoundOutput,  // 传入声音输出结构，包含当前音频信息
                                TargetSecondsPerFrame);  // 目标每帧的秒数，用于同步帧率
#endif
#endif

                        InitPlatform(&Platform, GameMemory.PlatformAPI);
                        // 在窗口中显示当前的缓冲区内容
                        Win32DisplayBufferInWindow(
                            &HighPriorityQueue,  //
                            DeviceContext,       // 设备上下文，用于渲染到窗口
                            DrawRegion, &RenderCommands, &FrameTempArena, Dimension.Width,
                            Dimension.Height);  // 全局后备缓冲区，包含要显示的图像

                        ReleaseDC(Window, DeviceContext);
                    }
                    // OutputDebugString(PrintBuffer);

                    game_input *Temp = NewInput;
                    NewInput = OldInput;
                    OldInput = Temp;

#if GAME_INTERNAL
                    END_BLOCK();
                    int64 EndCycleCount = __rdtsc();
                    int64 CyclesElapsed = EndCycleCount - LastCycleCount;
                    (void)CyclesElapsed;
                    // 获取当前时间点，作为当前帧结束的时间
                    LastCycleCount = EndCycleCount;

#endif
                    // real32 FrameMarkerSecondsElapse = 0.0f;
                    LARGE_INTEGER EndCounter = Win32GetWallClock();
                    FRAME_MARKER(Win32GetSecondsElapsed(LastCounter, EndCounter));
                    LastCounter = EndCounter;
                }
            } else {
            }
        } else {  // 如果窗口创建失败
                  // 这里可以处理窗口创建失败的逻辑
                  // 比如输出错误信息，或退出程序等
                  // TODO:
        }
    } else {  // 如果窗口类注册失败
              // 这里可以处理注册失败的逻辑
              // 比如输出错误信息，或退出程序等
              // TODO:
    }

    return 0;
}
